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 / 120064
Accepted
Geoff Patterson
Geoff Patterson
Asked: 2015-11-05 06:24:23 +0800 CST2015-11-05 06:24:23 +0800 CST 2015-11-05 06:24:23 +0800 CST

Por que a função LEN() subestima mal a cardinalidade no SQL Server 2014?

  • 772

Eu tenho uma tabela com uma coluna de string e um predicado que verifica se há linhas com um determinado comprimento. No SQL Server 2014, vejo uma estimativa de 1 linha, independentemente do comprimento que estou verificando. Isso está gerando planos muito ruins porque, na verdade, existem milhares ou até milhões de linhas e o SQL Server está optando por colocar essa tabela no lado externo de um loop aninhado.

Existe uma explicação para a estimativa de cardinalidade de 1,0003 para o SQL Server 2014 enquanto o SQL Server 2012 estima 31.622 linhas? Existe uma boa solução alternativa?

Aqui está uma pequena reprodução do problema:

-- Create a table with 1MM rows of dummy data
CREATE TABLE #customers (cust_nbr VARCHAR(10) NOT NULL)
GO

INSERT INTO #customers WITH (TABLOCK) (cust_nbr)
    SELECT TOP 1000000 
        CONVERT(VARCHAR(10),
        ROW_NUMBER() OVER (ORDER BY (SELECT NULL))) AS cust_nbr
    FROM master..spt_values v1
    CROSS JOIN master..spt_values v2
GO

-- Looking for string of a certain length.
-- While both CEs yield fairly poor estimates, the 2012 CE is much
-- more conservative (higher estimate) and therefore much more likely
-- to yield an okay plan rather than a drastically understimated loop join.
-- 2012: 31,622 rows estimated, 900K rows actual
-- 2014: 1 row estimated, 900K rows actual
SELECT COUNT(*)
FROM #customers
WHERE LEN(cust_nbr) = 6
OPTION (QUERYTRACEON 9481) -- Optionally, use 2012 CE
GO

Aqui está um script mais completo mostrando testes adicionais

Também li o whitepaper sobre o Estimador de cardinalidade do SQL Server 2014 , mas não encontrei nada que esclarecesse a situação.

sql-server sql-server-2014
  • 2 2 respostas
  • 1506 Views

2 respostas

  • Voted
  1. Best Answer
    Zane
    2015-11-05T07:02:15+08:002015-11-05T07:02:15+08:00

    Para o CE herdado, vejo que a estimativa é de 3,16228% das linhas - e essa é uma heurística de "número mágico" usada para coluna = predicados literais (existem outras heurísticas baseadas na construção de predicados - mas o LENenrolado em torno da coluna para o os resultados de CE herdados correspondem a essa estrutura de suposição). Você pode ver exemplos disso em uma postagem sobre Suposições de seletividade na ausência de estatísticas , de Joe Sack, e Estimativa de comparação constante-constante , de Ian Jose.

    -- Legacy CE: 31622.8 rows
    SELECT  COUNT(*)
    FROM    #customers
    WHERE   LEN(cust_nbr) = 6
    OPTION  ( QUERYTRACEON 9481); -- Legacy CE
    GO
    

    Agora, quanto ao novo comportamento do CE, parece que agora está visível para o otimizador (o que significa que podemos usar estatísticas). Fiz o exercício de observar a saída da calculadora abaixo e você pode observar a geração automática de estatísticas associada como um ponteiro:

    -- New CE: 1.00007 rows
    SELECT  COUNT(*)
    FROM    #customers
    WHERE   LEN(cust_nbr) = 6
    OPTION  ( QUERYTRACEON 2312 ); -- New CE
    GO
    
    -- View New CE behavior with 2363 (for supported option use XEvents)
    SELECT  COUNT(*)
    FROM    #customers
    WHERE   LEN(cust_nbr) = 6
    OPTION  (QUERYTRACEON 2312, QUERYTRACEON 2363, QUERYTRACEON 3604, RECOMPILE); -- New CE
    GO
    
    /*
    Loaded histogram for column QCOL:
    [tempdb].[dbo].[#customers].cust_nbr from stats with id 2
    Using ambient cardinality 1e+006 to combine distinct counts:
      999927
     
    Combined distinct count: 999927
    Selectivity: 1.00007e-006
    Stats collection generated:
      CStCollFilter(ID=2, CARD=1.00007)
          CStCollBaseTable(ID=1, CARD=1e+006 TBL: #customers)
     
    End selectivity computation
    */
     
    EXEC tempdb..sp_helpstats '#customers';
    
    
    --Check out AVG_RANGE_ROWS values (for example - plenty of ~ 1)
    DBCC SHOW_STATISTICS('tempdb..#customers', '_WA_Sys_00000001_B0368087');
    --That's my Stats name yours is subject to change
    

    Infelizmente, a lógica depende de uma estimativa do número de valores distintos, que não é ajustada para o efeito da LENfunção.

    Possível solução alternativa

    Você pode obter uma estimativa baseada em trie em ambos os modelos CE reescrevendo o LENcomo LIKE:

    SELECT COUNT_BIG(*)
    FROM #customers AS C
    WHERE C.cust_nbr LIKE REPLICATE('_', 6);
    

    plano LIKE


    Informações sobre sinalizadores de rastreamento usados:

    • 2363: mostra muitas informações, incluindo estatísticas sendo carregadas.
    • 3604: imprime a saída dos comandos DBCC na guia de mensagens.
    • 20
  2. Solomon Rutzky
    2015-11-05T07:27:26+08:002015-11-05T07:27:26+08:00

    Existe uma explicação para a estimativa de cardinalidade de 1,0003 para o SQL 2014 enquanto o SQL 2012 estima 31.622 linhas?

    Acho que a resposta de @Zane cobre muito bem essa parte.

    Existe uma boa solução alternativa?

    Você pode tentar criar uma coluna computada não persistente para LEN(cust_nbr)e (opcionalmente) criar um índice não clusterizado nessa coluna computada. Isso deve fornecer estatísticas precisas.

    Eu fiz alguns testes e aqui está o que eu encontrei:

    • As estatísticas foram criadas automaticamente na coluna computada não persistente, quando nenhum índice foi definido nela.
    • Adicionar o índice não agrupado na coluna computada não apenas não ajudou, mas também prejudicou um pouco o desempenho. CPU e tempos decorridos ligeiramente superiores. Custo estimado ligeiramente mais alto (seja o que for que valha a pena).
    • Tornar a coluna computada como PERSISTED(sem índice) foi melhor do que as outras duas variações. Linhas estimadas eram mais precisas. A CPU e o tempo decorrido foram melhores (como esperado, pois não precisava calcular nada por linha).
    • Não consegui criar um Índice Filtrado ou Estatísticas Filtradas na Coluna Computada (devido ao fato de estar sendo computada), mesmo que fosse PERSISTED:-(
    • 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