AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 84090
Accepted
Daniel Hutmacher
Daniel Hutmacher
Asked: 2014-12-03 04:52:58 +0800 CST2014-12-03 04:52:58 +0800 CST 2014-12-03 04:52:58 +0800 CST

ROW_NUMBER() sem PARTITION BY ainda gera o iterador de segmento

  • 772

Estou escrevendo em uma próxima postagem do meu blog sobre classificação e funções de janela agregadas, especificamente os iteradores do projeto de segmento e sequência. A forma como eu entendo é que Segment identifica linhas em um stream que constituem o fim/início de um grupo, então a seguinte consulta:

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

Usará Segmento para informar quando uma linha pertence a um grupo diferente da linha anterior. O iterador Sequence Project, em seguida, faz o cálculo do número de linha real, com base na saída do iterador de segmento.

Mas a consulta a seguir, usando essa lógica, não deve incluir um segmento, porque não há expressão de partição.

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

No entanto, quando tento essa hipótese, ambas as consultas usam um operador de segmento. A única diferença é que a segunda consulta não precisa de um GroupByno segmento. Isso não elimina a necessidade de um segmento em primeiro lugar?

Exemplo

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;
sql-server execution-plan
  • 2 2 respostas
  • 40617 Views

2 respostas

  • Voted
  1. Best Answer
    JNK
    2014-12-03T06:02:45+08:002014-12-03T06:02:45+08:00

    Encontrei esta postagem de blog de 6 anos mencionando o mesmo comportamento.

    Parece que ROW_NUMBER()sempre inclui um operador de segmento, seja PARTITION BYusado ou não. Se eu tivesse que adivinhar, diria que é porque facilita a criação de um plano de consulta no mecanismo.

    Se o segmento for necessário na maioria dos casos, e nos casos em que não for necessário for essencialmente uma não operação de custo zero, é muito mais simples incluí-lo sempre no plano quando uma função de janela é usada.

    • 12
  2. wBob
    2014-12-03T07:50:19+08:002014-12-03T07:50:19+08:00

    De acordo com o showplan.xsd para o plano de execução, GroupByaparece sem minOccursou maxOccursatributos que, portanto, padronizam para [1..1] tornando o elemento obrigatório, não necessariamente conteúdo. O elemento filho ColumnReferencedo tipo ( ColumnReferenceType) tem minOccurs0 e maxOccursilimitado [0..*], tornando-o opcional , portanto, o elemento vazio permitido. Se você tentar remover manualmente GroupBye forçar o plano, receberá o erro esperado:

    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].
    

    Curiosamente, descobri que você pode remover manualmente o operador Segmento para obter um plano válido para forçar que se parece com isso:

    insira a descrição da imagem aqui

    No entanto, quando você executa com esse plano (usando OPTION ( USE PLAN ... )), o Operador de segmento reaparece magicamente. Apenas mostra que o otimizador leva apenas os planos XML como um guia aproximado.

    Meu equipamento de teste:

    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>' )
    

    Retire o plano XML do equipamento de teste e salve-o como um .sqlplan para visualizar o plano menos o Segmento.

    PS Eu não gastaria muito tempo cortando planos SQL manualmente, como se você me conhecesse, você saberia que eu considero isso um trabalho ocupado que consome tempo e algo que eu nunca faria. Ah espera!? : )

    • 11

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve