ROW_NUMBER () बिना विभाजन के अभी भी सेगमेंट पुनरावृत्ति उत्पन्न करता है


11

मैं एक आगामी ब्लॉग पोस्ट पर रैंकिंग और कुल कार्य, विशेष रूप से सेगमेंट और अनुक्रम परियोजना पुनरावृत्तियों पर मेरा लेखन कर रहा हूं। जिस तरह से मैं इसे समझता हूं वह यह है कि सेगमेंट एक समूह में पंक्तियों की पहचान करता है जो एक समूह के अंत / शुरुआत का गठन करता है, इसलिए निम्न क्वेरी:

SELECT ROW_NUMBER() OVER (PARTITION BY someGroup ORDER BY someOrder)

सेगमेंट का उपयोग यह बताने के लिए करेगा कि कोई पंक्ति पिछली पंक्ति के अलावा किसी अन्य समूह से संबंधित है या नहीं। सीक्वेंस प्रोजेक्ट इटरेटर तब सेगमेंट इटरेटर के आउटपुट के आधार पर वास्तविक पंक्ति संख्या गणना करता है।

लेकिन निम्नलिखित तर्क, उस तर्क का उपयोग करते हुए, एक सेगमेंट को शामिल नहीं करना चाहिए, क्योंकि कोई विभाजन अभिव्यक्ति नहीं है।

SELECT ROW_NUMBER() OVER (ORDER BY someGroup, someOrder)

हालाँकि, जब मैं इस परिकल्पना को आज़माता हूँ तो ये दोनों प्रश्न एक सेगमेंट ऑपरेटर का उपयोग करते हैं। अंतर केवल इतना है कि GroupByसेगमेंट पर दूसरी क्वेरी की आवश्यकता नहीं है । क्या यह पहली जगह में सेगमेंट की आवश्यकता को समाप्त नहीं करता है?

उदाहरण

CREATE TABLE dbo.someTable (
    someGroup   int NOT NULL,
    someOrder   int NOT NULL,
    someValue   numeric(8, 2) NOT NULL,
    PRIMARY KEY CLUSTERED (someGroup, someOrder)
);

--- Query 1:
SELECT ROW_NUMBER() OVER (PARTITION BY someGroup ORDER BY someOrder)
FROM dbo.someTable;

--- Query 2:
SELECT ROW_NUMBER() OVER (ORDER BY someGroup, someOrder)
FROM dbo.someTable;

1
यद्यपि कोई विभाजन अभिव्यक्ति नहीं है, मुझे लगता है कि आप अभी भी तकनीकी रूप से विभाजन में सेट परिणाम को विभाजित कर रहे हैं, इस मामले में केवल एक ही है?
मार्क सिंकिनसन

क्यूपी एक खाली दिखाता है <GroupBy />इसलिए सेगमेंट वास्तव में कुछ भी नहीं करता है, लगभग, यह सीक्वेंस प्रोजेक्ट ऑपरेटर को सेगमेंट कॉलम का उत्पादन करता है। सेगमेंट ऑपरेटर के होने का कारण यह हो सकता है कि सीक्वेंस प्रोजेक्ट ऑपरेटर को अपना काम करने के लिए उस मूल्य की आवश्यकता हो।
मिकेल एरिकसन

यही मेरा सिद्धांत भी है। लेकिन
आशावादी

जवाबों:


12

मैंने उसी व्यवहार का उल्लेख करते हुए इस 6 साल पुराने ब्लॉग पोस्ट को पाया।

ऐसा लगता है कि ROW_NUMBER()हमेशा एक सेगमेंट ऑपरेटर शामिल है, चाहे PARTITION BYइसका उपयोग किया जाए या नहीं। अगर मुझे लगता है कि मैं यह कहना चाहूंगा क्योंकि यह इंजन पर एक क्वेरी प्लान बनाना आसान बनाता है।

यदि अधिकांश मामलों में सेगमेंट की आवश्यकता होती है, और उन मामलों में जहां इसकी आवश्यकता नहीं है, तो यह अनिवार्य रूप से शून्य-लागत वाला गैर-ऑपरेशन है, यह केवल एक विंडो फ़ंक्शन का उपयोग किए जाने पर योजना में हमेशा शामिल करने के लिए बहुत सरल है।


11

निष्पादन योजना के लिए showplan.xsd के अनुसार , GroupByबिना तत्व minOccursया maxOccursविशेषताओं के प्रकट होता है जो इसलिए [1..1] डिफ़ॉल्ट रूप से तत्व को अनिवार्य बनाता है, जरूरी नहीं कि सामग्री। प्रकार के बाल तत्व ColumnReference( ColumnReferenceType) में minOccurs0 और maxOccursअनबाउंड [0 .. *] है, जिससे यह वैकल्पिक हो जाता है , इसलिए रिक्त तत्व की अनुमति है। यदि आप मैन्युअल रूप से GroupByउस योजना को हटाने और बल देने का प्रयास करते हैं, जिसमें आपको अपेक्षित त्रुटि मिलती है:

Msg 6965, Level 16, State 1, Line 29
XML Validation: Invalid content. Expected element(s): '{http://schemas.microsoft.com/sqlserver/2004/07/showplan}GroupBy','{http://schemas.microsoft.com/sqlserver/2004/07/showplan}DefinedValues','{http://schemas.microsoft.com/sqlserver/2004/07/showplan}InternalInfo'. Found: element '{http://schemas.microsoft.com/sqlserver/2004/07/showplan}SegmentColumn' instead. Location: /*:ShowPlanXML[1]/*:BatchSequence[1]/*:Batch[1]/*:Statements[1]/*:StmtSimple[1]/*:QueryPlan[1]/*:RelOp[1]/*:SequenceProject[1]/*:RelOp[1]/*:Segment[1]/*:SegmentColumn[1].

दिलचस्प बात यह है कि आप इस तरह लगने वाले फोर्स के लिए एक मान्य योजना पाने के लिए मैन्युअल रूप से सेगमेंट ऑपरेटर को हटा सकते हैं:

यहाँ छवि विवरण दर्ज करें

हालाँकि जब आप उस योजना ( OPTION ( USE PLAN ... )सेगमेंट) का उपयोग करते हैं , तो सेगमेंट ऑपरेटर जादुई रूप से पुन: प्रकट होता है। बस ऑप्टिमाइज़र दिखाने के लिए जाता है केवल XML योजनाओं को एक मोटे गाइड के रूप में लेता है।

मेरा परीक्षण रिग:

USE tempdb
GO
SET NOCOUNT ON
GO
IF OBJECT_ID('dbo.someTable') IS NOT NULL DROP TABLE dbo.someTable
GO
CREATE TABLE dbo.someTable (
    someGroup   int NOT NULL,
    someOrder   int NOT NULL,
    someValue   numeric(8, 2) NOT NULL,
    PRIMARY KEY CLUSTERED (someGroup, someOrder)
);
GO

-- Generate some dummy data
;WITH cte AS (
SELECT TOP 1000 ROW_NUMBER() OVER ( ORDER BY ( SELECT 1 ) ) rn
FROM master.sys.columns c1
    CROSS JOIN master.sys.columns c2
    CROSS JOIN master.sys.columns c3
)
INSERT INTO dbo.someTable ( someGroup, someOrder, someValue )
SELECT rn % 333, rn % 444, rn % 55
FROM cte
GO


-- Try and force the plan
SELECT ROW_NUMBER() OVER (ORDER BY someGroup, someOrder)
FROM dbo.someTable
OPTION ( USE PLAN N'<?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.2" Build="12.0.2000.8" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">
  <BatchSequence>
    <Batch>
      <Statements>
        <StmtSimple StatementCompId="1" StatementEstRows="1000" StatementId="1" StatementOptmLevel="TRIVIAL" CardinalityEstimationModelVersion="120" StatementSubTreeCost="0.00596348" StatementText="SELECT ROW_NUMBER() OVER (ORDER BY someGroup, someOrder)&#xD;&#xA;FROM dbo.someTable" StatementType="SELECT" QueryHash="0x193176312402B8E7" QueryPlanHash="0x77F1D72C455025A4" RetrievedFromCache="true">
          <StatementSetOptions ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" ARITHABORT="true" CONCAT_NULL_YIELDS_NULL="true" NUMERIC_ROUNDABORT="false" QUOTED_IDENTIFIER="true" />
          <QueryPlan DegreeOfParallelism="1" CachedPlanSize="16" CompileTime="0" CompileCPU="0" CompileMemory="88">
            <OptimizerHardwareDependentProperties EstimatedAvailableMemoryGrant="131072" EstimatedPagesCached="65536" EstimatedAvailableDegreeOfParallelism="4" />
            <RelOp AvgRowSize="15" EstimateCPU="8E-05" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="1000" LogicalOp="Compute Scalar" NodeId="0" Parallel="false" PhysicalOp="Sequence Project" EstimatedTotalSubtreeCost="0.00596348">
              <OutputList>
                <ColumnReference Column="Expr1002" />
              </OutputList>
              <SequenceProject>
                <DefinedValues>
                  <DefinedValue>
                    <ColumnReference Column="Expr1002" />
                    <ScalarOperator ScalarString="row_number">
                      <Sequence FunctionName="row_number" />
                    </ScalarOperator>
                  </DefinedValue>
                </DefinedValues>

                <!-- Segment operator completely removed from plan -->
                <!--<RelOp AvgRowSize="15" EstimateCPU="2E-05" EstimateIO="0" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="1000" LogicalOp="Segment" NodeId="1" Parallel="false" PhysicalOp="Segment" EstimatedTotalSubtreeCost="0.00588348">
                  <OutputList>
                    <ColumnReference Database="[tempdb]" Schema="[dbo]" Table="[someTable]" Column="someGroup" />
                    <ColumnReference Database="[tempdb]" Schema="[dbo]" Table="[someTable]" Column="someOrder" />
                    <ColumnReference Column="Segment1003" />
                  </OutputList>
                  <Segment>
                    <GroupBy />
                    <SegmentColumn>
                      <ColumnReference Column="Segment1003" />
                    </SegmentColumn>-->


                    <RelOp AvgRowSize="15" EstimateCPU="0.001257" EstimateIO="0.00460648" EstimateRebinds="0" EstimateRewinds="0" EstimatedExecutionMode="Row" EstimateRows="1000" LogicalOp="Clustered Index Scan" NodeId="0" Parallel="false" PhysicalOp="Clustered Index Scan" EstimatedTotalSubtreeCost="0.00586348" TableCardinality="1000">
                      <OutputList>
                        <ColumnReference Database="[tempdb]" Schema="[dbo]" Table="[someTable]" Column="someGroup" />
                        <ColumnReference Database="[tempdb]" Schema="[dbo]" Table="[someTable]" Column="someOrder" />
                      </OutputList>
                      <IndexScan Ordered="true" ScanDirection="FORWARD" ForcedIndex="false" ForceSeek="false" ForceScan="false" NoExpandHint="false" Storage="RowStore">
                        <DefinedValues>
                          <DefinedValue>
                            <ColumnReference Database="[tempdb]" Schema="[dbo]" Table="[someTable]" Column="someGroup" />
                          </DefinedValue>
                          <DefinedValue>
                            <ColumnReference Database="[tempdb]" Schema="[dbo]" Table="[someTable]" Column="someOrder" />
                          </DefinedValue>
                        </DefinedValues>
                        <Object Database="[tempdb]" Schema="[dbo]" Table="[someTable]" Index="[PK__someTabl__7CD03C8950FF62C1]" IndexKind="Clustered" Storage="RowStore" />
                      </IndexScan>
                    </RelOp>

                <!--</Segment>
                </RelOp>-->
              </SequenceProject>
            </RelOp>

          </QueryPlan>
        </StmtSimple>
      </Statements>
    </Batch>
  </BatchSequence>
</ShowPlanXML>' )

परीक्षण रिग से XML योजना को काटें और इसे एक .sqlplan के रूप में सेव करें प्लान सेगमेंट देखने के लिए।

PS मैं SQL योजनाओं के आसपास मैन्युअल रूप से काटते हुए बहुत अधिक समय व्यतीत नहीं करूंगा क्योंकि यदि आप मुझे जानते हैं तो आपको पता होगा कि मैं इसे समय- व्यस्त काम के रूप में मानता हूं और कुछ ऐसा जो मैं कभी नहीं करूंगा। ओह रुको !? :)


आपके पास अपने हाथों पर बहुत अधिक समय है ... अच्छा काम!
मार्क सिंकिनसन

मार्क से सहमत हूँ। मैं ऐसी चीजें सीख रहा हूं, जिनके बारे में मैं पूछना भी नहीं चाहता था। धन्यवाद! :)
डैनियल हतमाकर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.