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 / 34047
Accepted
Mikael Eriksson
Mikael Eriksson
Asked: 2013-02-04 23:58:37 +0800 CST2013-02-04 23:58:37 +0800 CST 2013-02-04 23:58:37 +0800 CST

O elenco até o momento é sargável, mas é uma boa ideia?

  • 772

No SQL Server 2008, o tipo de dados de data foi adicionado.

A conversão de uma datetimecoluna para dateé sargável e pode usar um índice na datetimecoluna.

select *
from T
where cast(DateTimeCol as date) = '20130101';

A outra opção que você tem é usar um intervalo.

select *
from T
where DateTimeCol >= '20130101' and
      DateTimeCol < '20130102'

Essas consultas são igualmente boas ou uma deve ser preferida à outra?

sql-server
  • 2 2 respostas
  • 9374 Views

2 respostas

  • Voted
  1. Best Answer
    Martin Smith
    2013-02-05T02:39:53+08:002013-02-05T02:39:53+08:00

    O mecanismo por trás da sargabilidade do casting até hoje é chamado de busca dinâmica .

    O SQL Server chama uma função interna GetRangeThroughConvertpara obter o início e o fim do intervalo.

    Surpreendentemente, este não é o mesmo intervalo que seus valores literais.

    Criando uma tabela com uma linha por página e 1440 linhas por dia

    CREATE TABLE T
      (
         DateTimeCol DATETIME PRIMARY KEY,
         Filler      CHAR(8000) DEFAULT 'X'
      );
    
    WITH Nums(Num)
         AS (SELECT number
             FROM   spt_values
             WHERE  type = 'P'
                    AND number BETWEEN 1 AND 1440),
         Dates(Date)
         AS (SELECT {d '2012-12-30'} UNION ALL
             SELECT {d '2012-12-31'} UNION ALL
             SELECT {d '2013-01-01'} UNION ALL
             SELECT {d '2013-01-02'} UNION ALL
             SELECT {d '2013-01-03'})
    INSERT INTO T
                (DateTimeCol)
    SELECT DISTINCT DATEADD(MINUTE, Num, Date)
    FROM   Nums,
           Dates 
    

    Em seguida, correndo

    SET STATISTICS IO ON;
    SET STATISTICS TIME ON;
    
    SELECT *
    FROM   T
    WHERE  DateTimeCol >= '20130101'
           AND DateTimeCol < '20130102'
    
    SELECT *
    FROM   T
    WHERE  CAST(DateTimeCol AS DATE) = '20130101'; 
    

    A primeira consulta tem 1443leituras e a segunda 2883, portanto, está lendo um dia adicional inteiro e, em seguida, descartando-o contra um predicado residual.

    O plano mostra que o predicado de busca é

    Seek Keys[1]: Start: DateTimeCol > Scalar Operator([Expr1006]), 
                   End: DateTimeCol < Scalar Operator([Expr1007])
    

    Então, em vez de >= '20130101' ... < '20130102'ler > '20121231' ... < '20130102', descarta todas as 2012-12-31linhas.

    Outra desvantagem de confiar nele é que as estimativas de cardinalidade podem não ser tão precisas quanto na consulta de intervalo tradicional. Isso pode ser visto em uma versão corrigida do seu SQL Fiddle .

    Todas as 100 linhas na tabela agora correspondem ao predicado (com datas e horas separadas por 1 minuto, todas no mesmo dia).

    A segunda consulta (intervalo) estima corretamente que 100 corresponderá e usa uma verificação de índice clusterizado. A CAST( AS DATE)consulta estima incorretamente que apenas uma linha corresponderá e produz um plano com pesquisas de chave.

    As estatísticas não são completamente ignoradas. Se todas as linhas na tabela tiverem o mesmo datetimee corresponderem ao predicado (por exemplo , 20130101 00:00:00ou 20130101 01:00:00), o plano mostrará uma varredura de índice clusterizado com 31,6228 linhas estimadas.

    100 ^ 0.75 = 31.6228
    

    Portanto, nesse caso, parece que a estimativa é derivada desta fórmula :

    A tabela a seguir mostra o número de conjuntos adivinhados e a seletividade resultante em função da cardinalidade da tabela de entrada de N:

    | Conjuncts | Cardinality | Selectivity |
    |-----------|-------------|-------------|
    | 1         | N^(3/4)     | N^(-1/4)    |
    | 2         | N^(11/16)   | N^(-5/16)   |
    | 3         | N^(43/64)   | N^(-21/64)  |
    | 4         | N^(171/256) | N^(-85/256) |
    | 5         | N^(170/256) | N^(-86/256) |
    | 6         | N^(169/256) | N^(-87/256) |
    | 7         | N^(168/256) | N^(-88/256) |
    | ...       |             |             |
    | 175       | N^(0/256)   | N^(-1)      |
    

    Se todas as linhas na tabela tiverem o mesmo datetimee não corresponderem ao predicado (por exemplo 20130102 01:00:00, ), ele retornará à contagem de linhas estimada de 1 e ao plano com pesquisas.

    Para os casos em que a tabela possui mais de um DISTINCTvalor, as linhas estimadas parecem ser as mesmas como se a consulta estivesse procurando exatamente 20130101 00:00:00.

    Se o histograma estatístico tiver um passo em 2013-01-01 00:00:00.000então a estimativa será baseada no EQ_ROWS(ou seja, não levando em consideração outros horários naquela data). Caso contrário, se não houver nenhuma etapa, parece que ele usa as AVG_RANGE_ROWSetapas ao redor.

    Como datetimetem uma precisão de aproximadamente 3 ms em muitos sistemas, haverá muito poucos valores reais duplicados e esse número será 1.

    • 77
  2. Erik Darling
    2018-09-14T05:29:22+08:002018-09-14T05:29:22+08:00

    Eu sei que isso tem uma Great Answer® de longa data de Martin, mas eu queria adicionar algumas mudanças no comportamento aqui em versões mais recentes do SQL Server. Isso parece ter sido testado apenas até 2008R2.

    Com as novas USE HINTs que possibilitam algumas viagens no tempo de estimativa de cardinalidade, podemos ver quando as coisas mudaram.

    Usando a mesma configuração do SQL Fiddle.

    CREATE TABLE T ( ID INT IDENTITY PRIMARY KEY, DateTimeCol DATETIME, Filler CHAR(8000) NULL );
    
    CREATE INDEX IX_T_DateTimeCol ON T ( DateTimeCol );
    
    
    WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
         E02(N) AS (SELECT 1 FROM E00 a, E00 b),
         E04(N) AS (SELECT 1 FROM E02 a, E02 b),
         E08(N) AS (SELECT 1 FROM E04 a, E04 b),
         Num(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY E08.N) FROM E08)
    INSERT INTO T(DateTimeCol)
    SELECT TOP 100 DATEADD(MINUTE, Num.N, '20130101')
    FROM Num;
    

    Podemos testar os diferentes níveis assim:

    SELECT *
    FROM   T
    WHERE  CAST(DateTimeCol AS DATE) = '20130101'
    OPTION ( USE HINT ( 'QUERY_OPTIMIZER_COMPATIBILITY_LEVEL_100' ));
    GO
    
    SELECT *
    FROM   T
    WHERE  CAST(DateTimeCol AS DATE) = '20130101'
    OPTION ( USE HINT ( 'QUERY_OPTIMIZER_COMPATIBILITY_LEVEL_110' ));
    GO 
    
    SELECT *
    FROM   T
    WHERE  CAST(DateTimeCol AS DATE) = '20130101'
    OPTION ( USE HINT ( 'QUERY_OPTIMIZER_COMPATIBILITY_LEVEL_120' ));
    GO 
    
    SELECT *
    FROM   T
    WHERE  CAST(DateTimeCol AS DATE) = '20130101'
    OPTION ( USE HINT ( 'QUERY_OPTIMIZER_COMPATIBILITY_LEVEL_130' ));
    GO 
    
    SELECT *
    FROM   T
    WHERE  CAST(DateTimeCol AS DATE) = '20130101'
    OPTION ( USE HINT ( 'QUERY_OPTIMIZER_COMPATIBILITY_LEVEL_140' ));
    GO 
    
    SELECT *
    FROM   T
    WHERE  CAST(DateTimeCol AS DATE) = '20130101'
    OPTION ( USE HINT ( 'QUERY_OPTIMIZER_COMPATIBILITY_LEVEL_150' ));
    GO 
    

    Os planos para todos eles estão disponíveis aqui . Os níveis de compatibilidade 100 e 110 fornecem o plano de pesquisa de chave, mas começando com o nível de compatibilidade 120, começamos a obter o mesmo plano de varredura com estimativas de 100 linhas. Isso é verdade até o nível de compatibilidade 150.

    NOZES

    NOZES

    NOZES

    NOZES

    A estimativa de cardinalidade para os >= '20130101', < '20130102'planos permanece em 100, o que era esperado.

    • 24

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

    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

    Conceder acesso a todas as tabelas para um usuário

    • 5 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
    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
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +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