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 / 141999
Accepted
Vladimir Baranov
Vladimir Baranov
Asked: 2016-06-23 18:07:14 +0800 CST2016-06-23 18:07:14 +0800 CST 2016-06-23 18:07:14 +0800 CST

ROW_NUMBER() OVER (PARTITION BY B,A ORDER BY C) não usa índice em (A,B,C)

  • 772

Considere estas duas funções:

ROW_NUMBER() OVER (PARTITION BY A,B ORDER BY C)

ROW_NUMBER() OVER (PARTITION BY B,A ORDER BY C)

Tanto quanto eu entendo, eles produzem exatamente o mesmo resultado. Em outras palavras, a ordem em que você lista as colunas na PARTITION BYcláusula não importa.

Se houver um índice, (A,B,C)eu esperava que o otimizador usasse esse índice em ambas as variantes.

Mas, surpreendentemente, o otimizador decidiu fazer uma classificação extra explícita na segunda variante.

Eu vi isso no SQL Server 2008 Standard e no SQL Server 2014 Express.

Aqui está um script completo que usei para reproduzi-lo.

Tentei no Microsoft SQL Server 2014 - 12.0.2000.8 (X64) 20 de fevereiro de 2014 20:04:26 Copyright (c) Microsoft Corporation Express Edition (64 bits) no Windows NT 6.1 (Build 7601: Service Pack 1)

e Microsoft SQL Server 2014 (SP1-CU7) (KB3162659) - 12.0.4459.0 (X64) 27 de maio de 2016 15:33:17 Copyright (c) Microsoft Corporation Express Edition (64 bits) no Windows NT 6.1 (Build 7601: Service Pacote 1)

com o estimador de cardinalidade antigo e novo usando OPTION (QUERYTRACEON 9481)e OPTION (QUERYTRACEON 2312).

Configurar tabela, índice, dados de amostra

CREATE TABLE [dbo].[T](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [A] [int] NOT NULL,
    [B] [int] NOT NULL,
    [C] [int] NOT NULL,
    CONSTRAINT [PK_T] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, 
STATISTICS_NORECOMPUTE = OFF, 
IGNORE_DUP_KEY = OFF, 
ALLOW_ROW_LOCKS = ON, 
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

CREATE NONCLUSTERED INDEX [IX_ABC] ON [dbo].[T]
(
    [A] ASC,
    [B] ASC,
    [C] ASC
)WITH (PAD_INDEX = OFF, 
STATISTICS_NORECOMPUTE = OFF, 
SORT_IN_TEMPDB = OFF, 
DROP_EXISTING = OFF, 
ONLINE = OFF, 
ALLOW_ROW_LOCKS = ON, 
ALLOW_PAGE_LOCKS = ON)
GO

INSERT INTO [dbo].[T] ([A],[B],[C]) VALUES
(10, 20, 30),
(10, 21, 31),
(10, 21, 32),
(10, 21, 33),
(11, 20, 34),
(11, 21, 35),
(11, 21, 36),
(12, 20, 37),
(12, 21, 38),
(13, 21, 39);

Consultas

SELECT -- AB
    ID,A,B,C
    ,ROW_NUMBER() OVER (PARTITION BY A,B ORDER BY C) AS rnAB
FROM T
ORDER BY C
OPTION(RECOMPILE);

SELECT -- BA
    ID,A,B,C
    ,ROW_NUMBER() OVER (PARTITION BY B,A ORDER BY C) AS rnBA
FROM T
ORDER BY C
OPTION(RECOMPILE);

SELECT -- both
    ID,A,B,C
    ,ROW_NUMBER() OVER (PARTITION BY A,B ORDER BY C) AS rnAB
    ,ROW_NUMBER() OVER (PARTITION BY B,A ORDER BY C) AS rnBA
FROM T
ORDER BY C
OPTION(RECOMPILE);

Planos de execução

PARTIÇÃO POR A,B

AB

PARTIÇÃO POR B,A

BA

Ambos

Ambas

Como você pode ver, o segundo plano tem um Sort extra. Ordena por B,A,C. O otimizador, aparentemente, não é inteligente o suficiente para perceber que PARTITION BY B,Aé o mesmo PARTITION BY A,Be reclassificar os dados.

Curiosamente, a terceira consulta contém ambas as variantes ROW_NUMBERe não há classificação extra! O plano é o mesmo da primeira consulta. (O Projeto de Sequência tem expressão extra na Lista de Saída para a coluna extra, mas não Ordenação extra). Portanto, neste caso mais complicado, o otimizador parecia ser inteligente o suficiente para perceber que PARTITION BY B,Aé o mesmo que PARTITION BY A,B.

Na primeira e terceira consultas o operador Index Scan tem a propriedade Ordered:True, na segunda consulta é False.

Ainda mais interessante, se eu reescrever a terceira consulta assim (troque duas colunas):

SELECT -- both
    ID,A,B,C
    ,ROW_NUMBER() OVER (PARTITION BY B,A ORDER BY C) AS rnBA
    ,ROW_NUMBER() OVER (PARTITION BY A,B ORDER BY C) AS rnAB
FROM T
ORDER BY C
OPTION(RECOMPILE);

então o Sort extra aparece novamente!

Alguém poderia dar uma luz? O que está acontecendo no otimizador aqui?

sql-server sql-server-2008
  • 1 1 respostas
  • 12072 Views

1 respostas

  • Voted
  1. Best Answer
    Vladimir Baranov
    2016-08-04T05:24:34+08:002016-08-04T05:24:34+08:00

    Parece que não há uma boa "resposta" definitiva para a pergunta "o que está acontecendo no otimizador", a menos que você seja o desenvolvedor e conheça seus componentes internos.

    Vou juntar os comentários aqui.

    No geral, parece que seria muito duro chamá-lo de bug, porque o resultado final da consulta está correto. Em alguns casos, o plano de execução simplesmente não é ideal. ypercubeᵀᴹ , Martin Smith e Aaron Bertrand chamam isso de "otimização perdida".

    • Parece GROUP BY a,be GROUP BY b,aproduz planos idênticos, mas PARTITION BYnão pode usar a mesma transformação

    • Há outras otimizações ausentes também, onde as funções de janela com a mesma especificação de janela podem ter uma operação de classificação extra se separadas na lista de seleção por uma com uma especificação diferente.

    • Sim, isso parece outra otimização perdida, e há muitas delas. O otimizador é escrito por humanos e não é perfeito


    Há um artigo um tanto relacionado Índices Descendentes. Ordenação de índice, paralelismo e cálculos de classificação por Itzik Ben-Gan. Lá, Itzik discute índices descendentes e também dá um exemplo de como a direção da definição do índice afeta as funções da janela com partições. Ele mostra exemplos de consultas e planos gerados com ROW_NUMBERoperadores de classificação extras que o otimizador poderia ter evitado.


    Para mim, o resultado prático seria manter essa peculiaridade do otimizador em mente. Ao usar PARTITION BYas funções in window, sempre tente corresponder a ordem em que você lista as colunas PARTITION BYcom a ordem em que elas são listadas no índice. Mesmo que isso não deva importar.

    Outro lado dessa precaução é quando você revisa seus índices e decide trocar algumas colunas na definição do índice. Esteja ciente de que você pode afetar inadvertidamente algumas consultas existentes que aparentemente não deveriam ser afetadas. Na verdade, foi assim que percebi essa peculiaridade do otimizador.

    Caso contrário, o otimizador pode não conseguir usar o índice em todo o seu potencial. Mesmo que o otimizador escolha um plano ideal, esse plano pode mudar para menos ideal com uma alteração inocente na consulta, como alterar a ordem das colunas na SELECTinstrução.

    • 3

relate perguntas

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

  • Quanto "Padding" coloco em meus índices?

  • Existe um processo do tipo "práticas recomendadas" para os desenvolvedores seguirem para alterações no banco de dados?

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

  • Downgrade do SQL Server 2008 para 2005

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