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 / 226185
Accepted
Erik Darling
Erik Darling
Asked: 2019-01-03 10:16:12 +0800 CST2019-01-03 10:16:12 +0800 CST 2019-01-03 10:16:12 +0800 CST

Quando os predicados SARGable podem ser inseridos em uma CTE ou tabela derivada?

  • 772

Saco de areia

Enquanto trabalhava no Top Quality Blog Posts® , me deparei com alguns comportamentos do otimizador que achei muito interessantes. Eu não tenho uma explicação imediatamente, pelo menos não uma com a qual eu esteja feliz, então estou colocando aqui caso alguém inteligente apareça.

Se você quiser acompanhar, você pode pegar a versão 2013 do despejo de dados do Stack Overflow aqui . Estou usando a tabela Comentários, com um índice adicional.

CREATE INDEX [ix_ennui] ON [dbo].[Comments] ( [UserId], [Score] DESC );

Consulta Um

Quando eu consulto a tabela assim, recebo um plano de consulta estranho .

WITH x
    AS
     (
         SELECT   TOP 101
                  c.UserId, c.Text, c.Score
         FROM     dbo.Comments AS c
         ORDER BY c.Score DESC
     )
SELECT *
FROM   x
WHERE  x.Score >= 500;

NOZES

O predicado SARGable em Score não é inserido no CTE. Está em um operador de filtro muito mais tarde no plano.

NOZES

O que eu acho estranho, já que o ORDER BYestá na mesma coluna que o filtro.

Consulta Dois

Se eu alterar a consulta, ela é enviada.

WITH x
    AS
     (
         SELECT   c.UserId, c.Text, c.Score
         FROM     dbo.Comments AS c
     )
SELECT TOP 101 *
FROM   x
WHERE  x.Score >= 500
ORDER BY x.Score DESC;

O plano de consulta também muda e é executado muito mais rápido, sem derramamento no disco. Ambos produzem os mesmos resultados, com o predicado na varredura de índice não clusterizado.

NOZES

NOZES

Consulta três

Isso é o equivalente a escrever a consulta assim:

SELECT   TOP 101
         c.UserId, c.Text, c.Score
FROM     dbo.Comments AS c
WHERE c.Score >= 500
ORDER BY c.Score DESC;

Consulta Quatro

O uso de uma tabela derivada obtém o mesmo plano de consulta "ruim" que a consulta CTE inicial

SELECT *
FROM   (   SELECT   TOP 101
                    c.UserId, c.Text, c.Score
           FROM     dbo.Comments AS c
           ORDER BY c.Score DESC ) AS x
WHERE x.Score >= 500;

As coisas ficam ainda mais estranhas quando...

Eu altero a consulta para ordenar os dados em ordem crescente e o filtro para <=.

Para evitar fazer essa pergunta muito longa, vou colocar tudo junto.

Consultas

--Derived table
SELECT *
FROM   (   SELECT   TOP 101
                    c.UserId, c.Text, c.Score
           FROM     dbo.Comments AS c
           ORDER BY c.Score ASC ) AS x
WHERE x.Score <= 500;


--TOP inside CTE
WITH x
    AS
     (
         SELECT   TOP 101
                  c.UserId, c.Text, c.Score
         FROM     dbo.Comments AS c
         ORDER BY c.Score ASC
     )
SELECT *
FROM   x
WHERE  x.Score <= 500;


--Written normally
SELECT   TOP 101
         c.UserId, c.Text, c.Score
FROM     dbo.Comments AS c
WHERE c.Score <= 500
ORDER BY c.Score ASC;

--TOP outside CTE
WITH x
    AS
     (
         SELECT   c.UserId, c.Text, c.Score
         FROM     dbo.Comments AS c
     )
SELECT TOP 101 *
FROM   x
WHERE  x.Score <= 500
ORDER BY x.Score ASC;

Planos

Link do plano .

NOZES

Observe que nenhuma dessas consultas tira proveito do índice não clusterizado -- a única coisa que muda aqui é a posição do operador de filtro. Em nenhum caso o predicado é enviado para o acesso ao índice.

Aparece uma pergunta!

Existe uma razão pela qual um predicado SARGable pode ser empurrado em alguns cenários e não em outros? As diferenças dentro das consultas classificadas em ordem decrescente são interessantes, mas as diferenças entre aquelas e as que são ascendentes são bizarras.

Para quem estiver interessado, aqui estão os planos com apenas um índice em Score:

  • DESC
  • ASC
sql-server optimization
  • 1 1 respostas
  • 717 Views

1 respostas

  • Voted
  1. Best Answer
    Paul White
    2019-01-06T02:11:49+08:002019-01-06T02:11:49+08:00

    Há alguns problemas em jogo aqui.

    Empurrando predicados passadosTOP

    Atualmente, o otimizador não pode enviar um predicado além de um TOP, mesmo nos casos limitados em que seria seguro fazê-lo*. Essa limitação explica o comportamento de todas as consultas na pergunta em que o predicado está em um escopo mais alto que o TOP.

    A solução alternativa é executar a reescrita manualmente. A questão fundamental é semelhante ao caso de empurrar predicados além de uma função de janela , exceto que não há uma regra especializada correspondente como SelOnSeqPrj.

    Minha opinião pessoal é que uma regra de exploração como SelOnToppermanece não implementada porque as pessoas escreveram consultas deliberadamente TOPem um esforço para fornecer uma espécie de 'cerca de otimização'.

    * Geralmente, isso significa que o predicado deve aparecer na ORDER BYcláusula associada ao TOP, e a direção de qualquer desigualdade deve concordar com a direção da classificação. A transformação também precisaria levar em conta o comportamento de classificação de NULLs no SQL Server. No geral, as limitações provavelmente significam que essa transformação geralmente não seria útil o suficiente na prática para justificar os esforços adicionais de exploração.

    Problemas de custo

    Os planos de execução restantes na pergunta podem ser explicados como escolhas baseadas em custo devido à distribuição de valores na Scorecoluna (muito mais linhas <= 500 do que >= 500) e o efeito da meta de linha introduzida pelo TOP.

    Por exemplo, a consulta:

    --Written normally
    SELECT TOP (101)
        c.UserId, 
        c.[Text],
        c.Score
    FROM dbo.Comments AS c
    WHERE
        c.Score <= 500
    ORDER BY
        c.Score ASC;
    

    ... produz um plano com um predicado aparentemente não enviado em um Filtro:

    filtro atrasado devido ao objetivo de linha

    Observe que o Sort é estimado para produzir 101 linhas. Este é o efeito do objetivo de linha adicionado pelo Top. Isso afeta o custo estimado do Sort e do Filtro o suficiente para fazer parecer que esta é a opção mais barata. O custo estimado deste plano é de 2.401,39 unidades.

    Se desabilitarmos as metas de linha com uma dica de consulta:

    --Written normally
    SELECT TOP (101)
        c.UserId, 
        c.[Text],
        c.Score
    FROM dbo.Comments AS c
    WHERE
        c.Score <= 500
    ORDER BY
        c.Score ASC
    OPTION (USE HINT ('DISABLE_OPTIMIZER_ROWGOAL'));
    

    ...o plano de execução produzido é:

    plano sem meta de linha

    O predicado foi inserido na varredura como um predicado residual não sargável e o custo de todo o plano é de 2.402,32 unidades.

    Observe que <= 500não se espera que o predicado filtre nenhuma linha. Se você tivesse escolhido um número menor, como <= 50, o otimizador teria preferido o plano de predicado enviado, independentemente do efeito da meta de linha.

    Para a consulta com Score DESCe um Score >= 500predicado:

    --Written normally
    SELECT TOP (101)
        c.UserId, 
        c.[Text],
        c.Score
    FROM dbo.Comments AS c
    WHERE
        c.Score >= 500
    ORDER BY
        c.Score DESC;
    

    Agora, espera-se que o predicado seja muito seletivo, portanto, o otimizador opta por enviar o predicado e usar o índice não clusterizado com pesquisas:

    predicado seletivo

    Novamente, o otimizador considerou várias alternativas e escolheu esta como a opção aparentemente mais barata, como de costume.

    • 13

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