ट्रिगर सक्षम होने पर रिकॉर्ड को धीरे से हटाना


17

सोचा कि यह नीचे दिए गए लिंक के साथ हल किया गया है - काम के आसपास काम करता है - लेकिन पैच नहीं करता है। हल करने के लिए Microsoft समर्थन के साथ कार्य करना।

http://support.microsoft.com/kb/2606883

ठीक है तो मेरे पास एक मुद्दा है जिसे मैं स्टैकऑवरफ्लो में देखना चाहता हूं कि क्या किसी को एक विचार है।

ध्यान दें कि यह SQL Server 2008 R2 के साथ है

समस्या: 15000 रिकॉर्ड वाली तालिका से 3000 रिकॉर्ड हटाने में ट्रिगर सक्षम होने पर 3-4 मिनट लगते हैं और ट्रिगर अक्षम होने पर केवल 3-5 सेकंड।

टेबल सेटअप

दो तालिकाओं को हम मुख्य और माध्यमिक कहेंगे। द्वितीयक में उन वस्तुओं का रिकॉर्ड होता है जिन्हें मैं हटाना चाहता हूं जब मैं हटाता हूं तो मैं द्वितीयक तालिका में शामिल होता हूं। हटाए जाने के रिकॉर्ड के साथ द्वितीयक तालिका को पॉप्युलेट करने के लिए डिलीट स्टेटमेंट से पहले एक प्रक्रिया चलती है।

विवरण हटाएं:

DELETE FROM MAIN 
WHERE ID IN (
   SELECT Secondary.ValueInt1 
   FROM Secondary 
   WHERE SECONDARY.GUID = '9FFD2C8DD3864EA7B78DA22B2ED572D7'
);

इस तालिका में बहुत सारे स्तंभ हैं और लगभग 14 विभिन्न NC इंडेक्स हैं। इससे पहले कि मैं इस मुद्दे को ट्रिगर निर्धारित किया है मैं अलग अलग चीजों का एक गुच्छा की कोशिश की।

  • पृष्ठ लॉक करना चालू करें (हम डिफ़ॉल्ट रूप से बंद हो गए हैं)
  • मैन्युअल रूप से आँकड़े इकट्ठे हुए
  • आंकड़ों की विकलांग ऑटो सभा
  • सत्यापित सूचकांक स्वास्थ्य और विखंडन
  • टेबल से क्लस्टर इंडेक्स को गिरा दिया
  • निष्पादन योजना की जाँच की गई (कुछ भी नहीं है जो अनुपलब्ध अनुक्रमणिका के रूप में दिखा रहा है और लागत 70% थी जो अभिलेखों में शामिल / विलय के लिए लगभग 28 प्रतिशत थी।

ट्रिगर

तालिका में 3 ट्रिगर (सम्मिलित करने, अद्यतन करने और हटाने के लिए एक-एक) हैं। मैंने डिलीट ट्रिगर के लिए कोड को सिर्फ वापस करने के लिए संशोधित किया है, फिर एक का चयन करने के लिए कि यह कितनी बार निकाल दिया जाता है। यह पूरे ऑपरेशन के दौरान केवल एक बार फायर करता है (जैसा कि अपेक्षित है)।

ALTER TRIGGER [dbo].[TR_MAIN_RD] ON [dbo].[MAIN]
            AFTER DELETE
            AS  
                SELECT 1
                RETURN

संक्षेप में दुहराना

  • ट्रिगर ऑन स्टेटमेंट को पूरा होने में 3-4 मिनट का समय लगता है
  • ट्रिगर ऑफ - स्टेटमेंट को पूरा होने में 3-5 सेकंड लगते हैं

किसी के पास कोई विचार क्यों है?

यह भी ध्यान दें - इस वास्तुकला को बदलने के लिए नहीं, समाधान के रूप में निकालें अनुक्रमित, आदि जोड़ें। यह तालिका कुछ प्रमुख डेटा परिचालनों के लिए केंद्र का टुकड़ा है और हमें गतिरोध के बिना काम करने के लिए प्रमुख संगोष्ठी संचालन की अनुमति देने के लिए इसे (अनुक्रमित, पृष्ठ लॉकिंग, आदि) को ट्विक और ट्यून करना था।

यहाँ निष्पादन योजना xml है (निर्दोष लोगों की सुरक्षा के लिए नाम बदल दिए गए हैं)

<?xml version="1.0" encoding="utf-16"?>
<ShowPlanXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.1" Build="10.50.1790.0" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">
  <BatchSequence>
    <Batch>
      <Statements>
        <StmtSimple StatementCompId="1" StatementEstRows="185.624" StatementId="1" StatementOptmLevel="FULL" StatementOptmEarlyAbortReason="GoodEnoughPlanFound" StatementSubTreeCost="0.42706" StatementText="DELETE FROM MAIN WHERE ID IN (SELECT Secondary.ValueInt1 FROM Secondary WHERE Secondary.SetTMGUID = '9DDD2C8DD3864EA7B78DA22B2ED572D7')" StatementType="DELETE" QueryHash="0xAEA68D887C4092A1" QueryPlanHash="0x78164F2EEF16B857">
          <StatementSetOptions ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" ARITHABORT="false" CONCAT_NULL_YIELDS_NULL="true" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="true" />
          <QueryPlan CachedPlanSize="48" CompileTime="20" CompileCPU="20" CompileMemory="520">
            <RelOp AvgRowSize="9" EstimateCPU="0.00259874" EstimateIO="0.296614" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="185.624" LogicalOp="Delete" NodeId="0" Parallel="false" PhysicalOp="Clustered Index Delete" EstimatedTotalSubtreeCost="0.42706">
              <OutputList />
              <Update WithUnorderedPrefetch="true" DMLRequestSort="false">
                <Object Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Index="[IX_MAIN_02]" IndexKind="Clustered" />
                <Object Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Index="[PK_MAIN_ID]" IndexKind="NonClustered" />
                <Object Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Index="[UK_MAIN_01]" IndexKind="NonClustered" />
                <Object Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Index="[IX_MAIN_03]" IndexKind="NonClustered" />
                <Object Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Index="[IX_MAIN_04]" IndexKind="NonClustered" />
                <Object Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Index="[IX_MAIN_05]" IndexKind="NonClustered" />
                <Object Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Index="[IX_MAIN_06]" IndexKind="NonClustered" />
                <Object Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Index="[IX_MAIN_07]" IndexKind="NonClustered" />
                <Object Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Index="[IX_MAIN_08]" IndexKind="NonClustered" />
                <Object Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Index="[IX_MAIN_09]" IndexKind="NonClustered" />
                <Object Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Index="[IX_MAIN_10]" IndexKind="NonClustered" />
                <Object Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Index="[IX_MAIN_11]" IndexKind="NonClustered" />
                <Object Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Index="[UK_MAIN_12]" IndexKind="NonClustered" />
                <Object Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Index="[IX_MAIN_13]" IndexKind="NonClustered" />
                <RelOp AvgRowSize="15" EstimateCPU="1.85624E-05" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="185.624" LogicalOp="Top" NodeId="2" Parallel="false" PhysicalOp="Top" EstimatedTotalSubtreeCost="0.127848">
                  <OutputList>
                    <ColumnReference Column="Uniq1002" />
                    <ColumnReference Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Column="RelationshipID" />
                  </OutputList>
                  <Top RowCount="true" IsPercent="false" WithTies="false">
                    <TopExpression>
                      <ScalarOperator ScalarString="(0)">
                        <Const ConstValue="(0)" />
                      </ScalarOperator>
                    </TopExpression>
                    <RelOp AvgRowSize="15" EstimateCPU="0.0458347" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="185.624" LogicalOp="Left Semi Join" NodeId="3" Parallel="false" PhysicalOp="Merge Join" EstimatedTotalSubtreeCost="0.12783">
                      <OutputList>
                        <ColumnReference Column="Uniq1002" />
                        <ColumnReference Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Column="RelationshipID" />
                      </OutputList>
                      <Merge ManyToMany="false">
                        <InnerSideJoinColumns>
                          <ColumnReference Database="[MyDatabase]" Schema="[dbo]" Table="[Secondary]" Column="ValueInt1" />
                        </InnerSideJoinColumns>
                        <OuterSideJoinColumns>
                          <ColumnReference Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Column="ID" />
                        </OuterSideJoinColumns>
                        <Residual>
                          <ScalarOperator ScalarString="[MyDatabase].[dbo].[MAIN].[ID]=[MyDatabase].[dbo].[Secondary].[ValueInt1]">
                            <Compare CompareOp="EQ">
                              <ScalarOperator>
                                <Identifier>
                                  <ColumnReference Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Column="ID" />
                                </Identifier>
                              </ScalarOperator>
                              <ScalarOperator>
                                <Identifier>
                                  <ColumnReference Database="[MyDatabase]" Schema="[dbo]" Table="[Secondary]" Column="ValueInt1" />
                                </Identifier>
                              </ScalarOperator>
                            </Compare>
                          </ScalarOperator>
                        </Residual>
                        <RelOp AvgRowSize="19" EstimateCPU="0.0174567" EstimateIO="0.0305324" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="15727" LogicalOp="Index Scan" NodeId="4" Parallel="false" PhysicalOp="Index Scan" EstimatedTotalSubtreeCost="0.0479891" TableCardinality="15727">
                          <OutputList>
                            <ColumnReference Column="Uniq1002" />
                            <ColumnReference Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Column="ID" />
                            <ColumnReference Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Column="RelationshipID" />
                          </OutputList>
                          <IndexScan Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" ForceSeek="false" NoExpandHint="false">
                            <DefinedValues>
                              <DefinedValue>
                                <ColumnReference Column="Uniq1002" />
                              </DefinedValue>
                              <DefinedValue>
                                <ColumnReference Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Column="ID" />
                              </DefinedValue>
                              <DefinedValue>
                                <ColumnReference Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Column="RelationshipID" />
                              </DefinedValue>
                            </DefinedValues>
                            <Object Database="[MyDatabase]" Schema="[dbo]" Table="[MAIN]" Index="[PK_MAIN_ID]" IndexKind="NonClustered" />
                          </IndexScan>
                        </RelOp>
                        <RelOp AvgRowSize="11" EstimateCPU="0.00392288" EstimateIO="0.03008" EstimateRebinds="0" EstimateRewinds="0" EstimateRows="3423.53" LogicalOp="Index Seek" NodeId="5" Parallel="false" PhysicalOp="Index Seek" EstimatedTotalSubtreeCost="0.0340029" TableCardinality="171775">
                          <OutputList>
                            <ColumnReference Database="[MyDatabase]" Schema="[dbo]" Table="[Secondary]" Column="ValueInt1" />
                          </OutputList>
                          <IndexScan Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" ForceSeek="false" NoExpandHint="false">
                            <DefinedValues>
                              <DefinedValue>
                                <ColumnReference Database="[MyDatabase]" Schema="[dbo]" Table="[Secondary]" Column="ValueInt1" />
                              </DefinedValue>
                            </DefinedValues>
                            <Object Database="[MyDatabase]" Schema="[dbo]" Table="[Secondary]" Index="[IX_Secondary_01]" IndexKind="NonClustered" />
                            <SeekPredicates>
                              <SeekPredicateNew>
                                <SeekKeys>
                                  <Prefix ScanType="EQ">
                                    <RangeColumns>
                                      <ColumnReference Database="[MyDatabase]" Schema="[dbo]" Table="[Secondary]" Column="SetTMGUID" />
                                    </RangeColumns>
                                    <RangeExpressions>
                                      <ScalarOperator ScalarString="'9DDD2C8DD3864EA7B78DA22B2ED572D7'">
                                        <Const ConstValue="'9DDD2C8DD3864EA7B78DA22B2ED572D7'" />
                                      </ScalarOperator>
                                    </RangeExpressions>
                                  </Prefix>
                                </SeekKeys>
                              </SeekPredicateNew>
                            </SeekPredicates>
                          </IndexScan>
                        </RelOp>
                      </Merge>
                    </RelOp>
                  </Top>
                </RelOp>
              </Update>
            </RelOp>
          </QueryPlan>
        </StmtSimple>
      </Statements>
    </Batch>
  </BatchSequence>
</ShowPlanXML>

जवाबों:


12

पंक्ति-वर्ज़निंग ढांचे SQL सर्वर 2005 में शुरू की गई नई लेनदेन अलगाव स्तरों सहित सुविधाओं की एक संख्या है, का समर्थन करने के लिए किया जाता है READ_COMMITTED_SNAPSHOTऔर SNAPSHOT। यहां तक कि जब इन अलगाव के स्तर की न तो सक्षम किए गए हैं, रो-वर्ज़निंग अभी भी के लिए प्रयोग किया जाता है AFTERचलाता (की पीढ़ी की सुविधा के लिए insertedऔर deleted, मंगल, और (एक अलग संस्करण की दुकान में) ऑनलाइन अनुक्रमण छद्म टेबल)।

जैसा कि प्रलेखित है , इंजन किसी तालिका के प्रत्येक पंक्ति में एक 14-बाइट पोस्टफ़िक्स जोड़ सकता है जो कि इनमें से किसी भी उद्देश्य के लिए संस्करणबद्ध है। यह व्यवहार अपेक्षाकृत अच्छी तरह से जाना जाता है, जैसा कि एक सूचकांक की प्रत्येक पंक्ति में 14-बाइट डेटा के अतिरिक्त है जो कि एक पंक्ति-वर्जन आइसोलेशन स्तर सक्षम होने के साथ ऑनलाइन पुनर्निर्माण किया जाता है । यहां तक ​​कि जहां आइसोलेशन स्तर सक्षम नहीं हैं, एक अतिरिक्त बाइट को गैर-संकुल इंडेक्स में जोड़ा जाता है, जब केवल पुनर्निर्माण किया जाता है ONLINE

जहां एक AFTER ट्रिगर मौजूद है, और वर्जनिंग में प्रति पंक्ति 14 बाइट्स जोड़े जाएंगे, इससे बचने के लिए इंजन के भीतर एक ऑप्टिमाइज़ेशन मौजूद है , लेकिन जहां ROW_OVERFLOWया LOBआवंटन नहीं हो सकता है। व्यवहार में, इसका मतलब है कि पंक्ति का अधिकतम संभव आकार 8060 बाइट्स से कम होना चाहिए। अधिकतम संभव पंक्ति आकारों की गणना में , इंजन उदाहरण के लिए मानता है कि VARCHAR (460) कॉलम में 460 वर्ण हो सकते हैं।

AFTER UPDATEट्रिगर के साथ व्यवहार को देखना सबसे आसान है , हालांकि यही सिद्धांत लागू होता है AFTER DELETE। निम्न स्क्रिप्ट 8060 बाइट्स की अधिकतम-इन-पंक्ति लंबाई वाली तालिका बनाती है। डेटा एक पृष्ठ पर फिट बैठता है, उस पृष्ठ पर 13 बाइट्स मुक्त स्थान के साथ। एक नो-ऑप ट्रिगर मौजूद है, इसलिए पेज विभाजित हो गया है और सूचना को जोड़ा गया है:

USE Sandpit;
GO
CREATE TABLE dbo.Example
(
    ID          integer NOT NULL IDENTITY(1,1),
    Value       integer NOT NULL,
    Padding1    char(42) NULL,
    Padding2    varchar(8000) NULL,

    CONSTRAINT PK_Example_ID
    PRIMARY KEY CLUSTERED (ID)
);
GO
WITH
    N1 AS (SELECT 1 AS n UNION ALL SELECT 1),
    N2 AS (SELECT L.n FROM N1 AS L CROSS JOIN N1 AS R),
    N3 AS (SELECT L.n FROM N2 AS L CROSS JOIN N2 AS R),
    N4 AS (SELECT L.n FROM N3 AS L CROSS JOIN N3 AS R)
INSERT TOP (137) dbo.Example
    (Value)
SELECT
    ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM N4;
GO
ALTER INDEX PK_Example_ID 
ON dbo.Example 
REBUILD WITH (FILLFACTOR = 100);
GO
SELECT
    ddips.index_type_desc,
    ddips.alloc_unit_type_desc,
    ddips.index_level,
    ddips.page_count,
    ddips.record_count,
    ddips.max_record_size_in_bytes
FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID(N'dbo.Example', N'U'), 1, 1, 'DETAILED') AS ddips
WHERE
    ddips.index_level = 0;
GO
CREATE TRIGGER ExampleTrigger
ON dbo.Example
AFTER DELETE, UPDATE
AS RETURN;
GO
UPDATE dbo.Example
SET Value = -Value
WHERE ID = 1;
GO
SELECT
    ddips.index_type_desc,
    ddips.alloc_unit_type_desc,
    ddips.index_level,
    ddips.page_count,
    ddips.record_count,
    ddips.max_record_size_in_bytes
FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID(N'dbo.Example', N'U'), 1, 1, 'DETAILED') AS ddips
WHERE
    ddips.index_level = 0;
GO
DROP TABLE dbo.Example;

स्क्रिप्ट नीचे दिखाए गए आउटपुट का उत्पादन करती है। एकल-पृष्ठ तालिका दो पृष्ठों में विभाजित है, और अधिकतम भौतिक पंक्ति की लंबाई 57 से 71 बाइट्स (पंक्ति-संस्करण जानकारी के लिए = +14 बाइट्स) से बढ़ गई है।

अद्यतन उदाहरण

DBCC PAGEदिखाता है कि एकल अद्यतन पंक्ति में है Record Attributes = NULL_BITMAP VERSIONING_INFO Record Size = 71, जबकि तालिका में अन्य सभी पंक्तियाँ हैं Record Attributes = NULL_BITMAP; record Size = 57

एक ही स्क्रिप्ट, UPDATEएक एकल पंक्ति द्वारा प्रतिस्थापित किया गयाDELETE दिखाए गए आउटपुट का उत्पादन करती है:

DELETE dbo.Example
WHERE ID = 1;

उदाहरण हटाएं

कुल (निश्चित रूप से!) में एक कम पंक्ति है, लेकिन अधिकतम भौतिक पंक्ति का आकार नहीं बढ़ा है। पंक्ति संस्करण जानकारी केवल ट्रिगर छद्म तालिकाओं के लिए आवश्यक पंक्तियों में जोड़ी जाती है, और उस पंक्ति को अंततः हटा दिया गया था। हालाँकि पेज स्प्लिट रहता है। यह पृष्ठ-विभाजन गतिविधि धीमी प्रदर्शन के लिए जिम्मेदार है जब ट्रिगर मौजूद था। यदि Padding2स्तंभ की परिभाषा से बदल दिया गया varchar(8000)है varchar(7999), तो पृष्ठ अब विभाजित नहीं होता है।

SQL सर्वर MVP दिमित्री कोरोटकेविच द्वारा इस ब्लॉग पोस्ट को भी देखें , जो विखंडन पर प्रभाव पर भी चर्चा करता है।



5

अच्छी तरह से यहाँ Microsoft से आधिकारिक प्रतिक्रिया है ... जो मुझे लगता है कि एक प्रमुख डिजाइन दोष है।

11/14/2011 - आधिकारिक प्रतिक्रिया बदल गई है। वे लेन-देन लॉग का उपयोग नहीं कर रहे हैं जैसा कि पहले कहा गया है। बदले हुए डेटा को कॉपी करने के लिए आंतरिक स्टोर (पंक्ति स्तर) का उपयोग कर रहे हैं। वे अभी भी यह निर्धारित नहीं कर सकते हैं कि यह इतना लंबा क्यों है।

हमने डिलीट ट्रिगर्स के बदले ट्रिगर्स के बदले उपयोग करने का निर्णय लिया।

ट्रिगर का AFTER हिस्सा हमें डिलीट पूरा होने के बाद ट्रांजैक्शन लॉग के माध्यम से पढ़ना पड़ता है और ट्रिगर इन्सर्ट / डिलीट टेबल का निर्माण करना पड़ता है। यह वह जगह है जहाँ हम समय की विशाल राशि खर्च करते हैं और ट्रिगर के AFTER भाग के लिए डिज़ाइन द्वारा होते हैं। ट्रिगर का INSTEAD लेनदेन लॉग को स्कैन करने और सम्मिलित / हटाए गए तालिका के निर्माण के इस व्यवहार को रोक देगा। इसके अलावा, जैसा कि यह देखा गया कि यदि हम सभी स्तंभों को नवरच (अधिकतम) के साथ छोड़ते हैं, तो चीजें बहुत तेज होती हैं, जो इस तथ्य के कारण समझ में आता है कि इसे LOB डेटा माना जाता है। कृपया इन-रो डेटा के बारे में अधिक सूचना देने के लिए नीचे दिए गए लेख को देखें:

http://msdn.microsoft.com/en-us/library/ms189087.aspx

सारांश: हटाए जाने के बाद हस्तांतरण ट्रिगर के माध्यम से वापस स्कैन करने की आवश्यकता होती है, फिर हमें निर्माण और सम्मिलित / हटाए गए तालिका को लेन-देन लॉग और समय के अधिक उपयोग की आवश्यकता होती है।

तो एक कार्य योजना के रूप में, इस समय हम यही सुझाव देते हैं:

A) Limit the number of rows deleted in each transaction or
B) Increase timeout settings or
C) Don't use AFTER trigger or trigger at all or
D) Limit usage of nvarchar(max) datatypes.

2

योजना के अनुसार सब कुछ सही हो रहा है। आप एक IN के बजाय एक JOIN के रूप में डिलीट लिखने की कोशिश कर सकते हैं जिससे आपको एक अलग योजना मिलेगी।

DELETE m
FROM MAIN m
JOIN Secondary s ON m.ID = s.ValueInt1
AND s.SetTMGUID = '9DDD2C8DD3864EA7B78DA22B2ED572D7'

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.