चयन में बयान की प्रगति


14

हमारे ईटीएल प्रवाह में एक लंबे समय तक चलने वाला चयन इंटो-स्टेटमेंट है, जो मक्खी पर एक तालिका बना रहा है, और इसे कई सौ मिलियन रिकॉर्डों के साथ आबाद कर रहा है।

कथन कुछ इस प्रकार है SELECT ... INTO DestTable FROM SrcTable

निगरानी के उद्देश्यों के लिए, हम इस कथन की प्रगति का एक मोटा विचार प्राप्त करना चाहते हैं, जबकि यह निष्पादित कर रहा है (लगभग। पंक्तिबद्ध, बाइट्स की लिखित संख्या, या समान)।

हमने बिना किसी लाभ के निम्नलिखित कोशिश की:

-- Is blocked by the SELECT INTO statement:
select count(*) from DestTable with (nolock)

-- Returns 0, 0:
select rows, rowmodctr
from sysindexes with (nolock)
where id = object_id('DestTable')

-- Returns 0:
select rows
from sys.partitions
where object_id = object_id('DestTable')

इसके अलावा, हम लेन-देन को देख सकते हैं sys.dm_tran_active_transactions, लेकिन मैं किसी दिए गए पर प्रभावित पंक्तियों की गिनती प्राप्त करने का एक तरीका नहीं ढूंढ पा रहा था transaction_id( @@ROWCOUNTशायद कुछ इसी तरह के transaction_idतर्क के साथ)।

मैं समझता हूं कि SQL सर्वर पर SELECT INTO-statement एक में DDL और DML स्टेटमेंट दोनों है, और इस तरह, अंतर्निहित तालिका निर्माण एक लॉकिंग ऑपरेशन होगा। मुझे अभी भी लगता है कि बयान चलने के दौरान किसी प्रकार की प्रगति की जानकारी प्राप्त करने के लिए कुछ चतुर तरीका होना चाहिए।


यदि आपने एक वैश्विक अस्थायी तालिका ## टेबल का उपयोग किया है, तो क्या आप पहले से लिखे गए रिकॉर्डों की संख्या प्राप्त करने और कुल रिकॉर्ड की मात्रा प्राप्त करने के लिए ## टेबल पर सूचकांक कॉलम पर गिनती के साथ चयन कर सकते हैं?
कोवगेक

जवाबों:


6

मुझे लगता है कि rowsमें sys.partitionsअभी तक प्रतिबद्ध नहीं होने के कारण 0 है। लेकिन इसका मतलब यह नहीं है कि एसक्यूएल सर्वर इस बात से अनजान है कि अगर लेन-देन होता है तो वहां क्या होगा। कुंजी यह याद रखने में है कि सभी ऑपरेशन बफ़र पूल (यानी मेमोरी) से होकर गुजरते हैं, भले ही ऑपरेशन के कमिट या रोलबैक की परवाह किए बिना। इसलिए, हम sys.dm_os_buffer_descriptorsउस जानकारी के लिए देख सकते हैं :

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

SELECT  --OBJECT_NAME(sp.[object_id]) AS [TableName], sdobd.*, '---', sp.*, '---', sau.*
       SUM(sdobd.[row_count]) AS [BufferPoolRows],
       SUM(sp.[rows]) AS [AllocatedRows],
       COUNT(*) AS [DataPages]
FROM sys.dm_os_buffer_descriptors sdobd
INNER JOIN  sys.allocation_units sau
        ON sau.[allocation_unit_id] = sdobd.[allocation_unit_id]
INNER JOIN  sys.partitions sp
        ON  (   sau.[type] = 1
            AND sau.[container_id] = sp.[partition_id]) -- IN_ROW_DATA
        OR  (   sau.[type] = 2
            AND sau.[container_id] = sp.[hobt_id]) -- LOB_DATA
        OR  (   sau.[type] = 3
            AND sau.[container_id] = sp.[partition_id]) -- ROW_OVERFLOW_DATA
WHERE   sdobd.[database_id] = DB_ID()
AND     sdobd.[page_type] = N'DATA_PAGE'
AND     sp.[object_id] = (SELECT so.[object_id]
                          FROM   sys.objects so
                          WHERE  so.[name] = 'TestDump')

यदि आप विवरण देखना चाहते हैं, तो SELECTसूची में आइटम की पहली पंक्ति को अनइंस्टॉल करें , शेष 3 पंक्तियों पर टिप्पणी करें।

मैंने एक सत्र में निम्नलिखित को चलाकर और फिर बार-बार दूसरे में ऊपर दिए गए क्वेरी को चलाकर परीक्षण किया।

SELECT so1.*
INTO   dbo.TestDump
FROM   sys.objects so1
CROSS JOIN sys.objects so2
CROSS JOIN sys.objects so3;

1
यह रचनात्मक है। बस एक चेतावनी जोड़ना चाहते हैं कि एक बड़े बफर पूल की गणना बहुत धीमी है।
यूएसआर

1
यह मान लेता है कि अभी तक बफर पूल से कोई पृष्ठ नहीं निकाला गया है।
मार्टिन स्मिथ

@MartinSmith क्या पृष्ठों को कमिट करने से पहले बेदखल किया जा सकता है?
सोलोमन रटज़की

5
@srutzky - हाँ। लेन-देन लॉग में रोलबैक के लिए आवश्यक सभी जानकारी है। गंदे पृष्ठों को डिस्क पर लिखा जा सकता है - जैसे एक चौकी पर या एगर लेखक द्वारा विशेष रूप से इस मामले में फिर बफर पूल से हटा दिया जाता है।
मार्टिन स्मिथ

7

निगरानी के उद्देश्यों के लिए, हम इस कथन की प्रगति का एक मोटा विचार प्राप्त करना चाहेंगे, जबकि यह निष्पादित हो रहा है।

एक बंद या चल रहा है?

यदि यह एक ऐसी आवश्यकता है, जो पहले से अनुमानित हो * तो आप उपयोग कर सकते हैं sys.dm_exec_query_profiles

कनेक्शन 1 (सत्र 55)

SET STATISTICS XML ON

SELECT so1.*
INTO   dbo.TestDump
FROM   sys.all_objects so1
CROSS JOIN sys.all_objects so2
CROSS JOIN sys.all_objects so3
CROSS JOIN sys.all_objects so4
CROSS JOIN sys.all_objects so5;

कनेक्शन 2

select row_count
from sys.dm_exec_query_profiles
WHERE physical_operator_name = 'Table Insert' 
    AND session_id = 55;

यदि समानताSELECT INTO का उपयोग कर रहे हैं , तो आपको दी गई पंक्तियों की गणना करने की आवश्यकता हो सकती है ।

* सत्र आप इस DMV का उपयोग कर की निगरानी करना चाहते आंकड़े संग्रह प्रयोग करने के लिए सक्षम होना चाहिए SET STATISTICS PROFILE ONया SET STATISTICS XML ON। SSMS से "वास्तविक" निष्पादन योजना के लिए अनुरोध करने के साथ ही काम करता है (क्योंकि यह बाद के विकल्प को निर्धारित करता है)।


लगता है कि मैं इस फ़रवरी को +1 में भूल गया, लेकिन मैं इसके बारे में पूरी तरह से नहीं भूल पाया :)। मैंने अभी इस संबंधित प्रश्न पर इसका उपयोग किया है क्योंकि ओपी कम से कम 2014 पर है: dba.stackexchange.com/questions/139191/… इसे इंगित करने के लिए धन्यवाद; यह काफी काम DMV :-) है
सोलोमन रटज़्स्की

2
@srutzky हां यह बहुत उपयोगी है। और SSMS 2016 लाइव निष्पादन योजनाओं का उपयोग किया। msdn.microsoft.com/en-gb/library/dn831878.aspx
मार्टिन स्मिथ

5

मुझे नहीं लगता कि पंक्ति गणना प्राप्त करने का कोई तरीका है, लेकिन आप डेटा की मात्रा को देखकर अनुमान लगा सकते हैं:

SELECT writes 
  FROM sys.dm_exec_requests WHERE session_id = <x>;

SELECT COUNT(*) FROM sys.dm_db_database_page_allocations
(<dbid>, OBJECT_ID(N'dbo.newtablename'), 0, NULL, 'LIMITED');

यदि आपको इस बात का अंदाजा है कि काम पूरा होने के बाद कितने पृष्ठों पर ढेर लगना चाहिए, तो आपको% पूरा करने में सक्षम होना चाहिए। तालिका बड़ी होने के बाद उत्तरार्द्ध क्वेरी तेज़ नहीं होगी। और शायद ऊपर के तहत चलाने के लिए सबसे सुरक्षित READ UNCOMMITTED(और यह अक्सर ऐसा नहीं है जो मैं सुझाता हूं, किसी भी चीज के लिए)।


4

यदि आप INSERTए से बदल सकते हैं

SELECT ... INTO DestTable FROM SrcTable

को

INSERT DestTable SELECT ... FROM SrcTable

तब आपकी select count(*) from DestTable with (nolock)क्वेरी काम करेगी।

यदि यह संभव नहीं है, तो आप क्वेरी को कितने लिखते हैं, इसकी निगरानी के लिए आप sp_WhoIsActive (या DMVs में तल्लीन) का उपयोग कर सकते हैं। यदि आप इसे सामान्य रूप से लिखते हैं तो यह संख्या पंक्तिबद्ध होती है, लेकिन यदि आप सामान्य रूप से आधार बनाते हैं तो यह उपयोगी होगा।

यदि आप जोड़ते हैं तो आपको उपरोक्त के साथ न्यूनतम लॉगिंग प्राप्त करने में सक्षम होना चाहिए ।INSERTWITH (TABLOCK)


इस टिप्पणी के लिए धन्यवाद। हम न्यूनतम लॉगिंग प्राप्त करना चाहते हैं, यही वजह है कि हम SELECT ... INTO दृष्टिकोण का उपयोग कर रहे हैं (और इसलिए भी क्योंकि हम आलसी हैं ...)
Dan

1
INSERTयदि आप जोड़ते हैं तो आपको उपर्युक्त के साथ न्यूनतम लॉगिंग प्राप्त करने में सक्षम होना चाहिएWITH(TABLOCK)
जेम्स एंडरसन

@JamesAnderson - यदि तालिका को एक ढेर के रूप में छोड़ दिया जाता है, तो यह BULK_OPERATIONलॉक होने के कारण फिर से अवरुद्ध हो जाएगा ।
मार्टिन स्मिथ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.