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 / 151995
Accepted
James Lupolt
James Lupolt
Asked: 2016-10-12 09:10:46 +0800 CST2016-10-12 09:10:46 +0800 CST 2016-10-12 09:10:46 +0800 CST

Alterações nas estimativas em predicados que contêm SUBSTRING () no SQL Server 2016?

  • 772

Existe alguma documentação ou pesquisa sobre alterações no SQL Server 2016 para como a cardinalidade é estimada para predicados contendo SUBSTRING () ou outras funções de string?

A razão pela qual estou perguntando é que eu estava olhando para uma consulta cujo desempenho degradou no modo de compatibilidade 130 e o motivo foi relacionado a uma alteração na estimativa do número de linhas que correspondem a uma cláusula WHERE que continha uma chamada para SUBSTRING (). Corrigi o problema com uma reescrita de consulta, mas gostaria de saber se alguém conhece alguma documentação sobre alterações nessa área no SQL Server 2016.

O código de demonstração está abaixo. As estimativas são muito próximas neste caso de teste, mas a precisão varia dependendo dos dados.

No caso de teste, no nível de compatibilidade 120, o SQL Server parece estar usando o histograma para a estimativa, enquanto no nível de compatibilidade 130, o SQL Server parece assumir 10% fixos das correspondências da tabela.

CREATE DATABASE MyStringTestDB;
GO
USE MyStringTestDB;
GO
DROP TABLE IF EXISTS dbo.StringTest;
CREATE TABLE dbo.StringTest ( [TheString] varchar(15) );
GO
INSERT INTO dbo.StringTest
VALUES
( 'Y5_CLV' );
INSERT INTO dbo.StringTest
VALUES
( 'Y5_EG3' );
INSERT INTO dbo.StringTest
VALUES
( 'ZY_NE' );
INSERT INTO dbo.StringTest
VALUES
( 'ZY_PQT' );
INSERT INTO dbo.StringTest
VALUES
( 'ZY_T2V' );
INSERT INTO dbo.StringTest
VALUES
( 'ZY_TT4' );
INSERT INTO dbo.StringTest
VALUES
( 'ZY_ZKK' );
INSERT INTO dbo.StringTest
VALUES
( 'ZZ_LW6' );
INSERT INTO dbo.StringTest
VALUES
( 'ZZ_QO3' );
INSERT INTO dbo.StringTest
VALUES
( 'ZZ_TZ7' );
INSERT INTO dbo.StringTest
VALUES
( 'ZZ_UZZ' );

CREATE CLUSTERED INDEX IX_Clustered ON dbo.StringTest (TheString);

/* 
Uses fixed % for estimate; 1.1 rows estimated in this case.
    Plan for computation:
        CSelCalcFixedFilter (0.1) <----
            Selectivity: 0.1
*/
ALTER DATABASE MyStringTestDB SET compatibility_level = 130;
GO
SELECT * 
FROM dbo.StringTest 
WHERE SUBSTRING(TheString, 1, CHARINDEX('_',TheString) - 1) = 'ZZ'
OPTION (QUERYTRACEON 2363, QUERYTRACEON 3604);

/* 
Uses histogram to get estimate of 1
 CSelCalcPointPredsFreqBased <----
      Distinct value calculation:
          CDVCPlanLeaf
              0 Multi-Column Stats, 1 Single-Column Stats, 0 Guesses
      Individual selectivity calculations:
          (none)
    Loaded histogram for column QCOL: [DBA].[dbo].[StringTest].TheString from stats with id 1
*/
ALTER DATABASE MyStringTestDB SET compatibility_level = 120;
GO
SELECT * 
FROM dbo.StringTest 
WHERE SUBSTRING(TheString, 1, CHARINDEX('_',TheString) - 1) = 'ZZ'
OPTION (QUERYTRACEON 2363, QUERYTRACEON 3604);

/*
-- Simpler rewrite; works fine in both compat levels and gets better estimate.
SELECT * 
FROM dbo.StringTest 
WHERE TheString LIKE 'ZZ[_]%'
OPTION (QUERYTRACEON 2363, QUERYTRACEON 3604);
*/
sql-server optimization
  • 1 1 respostas
  • 387 Views

1 respostas

  • Voted
  1. Best Answer
    Martin Smith
    2016-10-23T11:56:02+08:002016-10-23T11:56:02+08:00

    Não tenho conhecimento de nenhuma documentação. Eu examinei isso e fiz algumas observações, no entanto, que são muito longas para um comentário.

    A estimativa de 10% nem sempre é uma degradação. Veja o exemplo a seguir.

    TRUNCATE TABLE dbo.StringTest
    
    INSERT INTO dbo.StringTest
    SELECT TOP (1000000) 'ZZ_' + LEFT(NEWID(), 12)
    FROM   master..spt_values v1,
           master..spt_values v2;
    

    e a WHEREcláusula em sua pergunta.

    WHERE SUBSTRING(TheString, 1, CHARINDEX('_',TheString) - 1) = 'ZZ'
    

    A tabela contém um milhão de linhas. Todos eles correspondem ao predicado. No nível de compatibilidade 130, o palpite de 10% produz uma estimativa de 100.000. Abaixo de 120, as linhas estimadas são 1,03913.

    O comportamento 120 usa o histograma, mas apenas para obter o número de linhas distintas. O vetor de densidade no meu caso mostra 1,039131E-06 e é multiplicado pela cardinalidade da tabela para obter a contagem de linhas estimada. Todos os valores são de fato diferentes, mas todos correspondem ao predicado.

    Rastrear o query_optimizer_estimate_cardinalityevento estendido mostra que abaixo de 130 há dois <StatsCollection Name="CStCollFilter"eventos diferentes. O primeiro estima 100.000. O segundo carrega o histograma e usa o CSelCalcPointPredsFreqBased/DistinctCountCalculator para obter a estimativa de 1,04. Este segundo resultado parece não utilizado.

    O comportamento que você observou não é aplicado consistentemente em 130. Acrescentei que ORDER BY TheStringesperava que isso fosse uma vitória clara para o estimador 130, pois o 120 luta com uma concessão de memória para uma linha, mas essa pequena alteração foi suficiente para reduzir as linhas estimadas para 1,03913 no caso 130 também.

    A adição OPTION (QUERYRULEOFF SelectToFilter)reverte a estimativa que entra na classificação para 100.000, mas a concessão de memória não aumenta e as estimativas que saem da classificação ainda são baseadas nos valores distintos da tabela.

    insira a descrição da imagem aqui

    Da mesma forma, ajustar o limite de custo para paralelismo para que a consulta obtenha um plano paralelo foi suficiente no caso 130 para reverter para a estimativa mais baixa. A adição QUERYTRACEON 8757também causa a estimativa mais baixa. Parece que a estimativa de 10% é mantida apenas para planos triviais.

    Sua reescrita proposta com

    WHERE TheString LIKE 'ZZ[_]%'
    

    Mostra estimativas muito superiores a ambos. A saída para isso é

      CSelCalcTrieBased
    
          Column: QCOL: [MyStringTestDB].[dbo].[StringTest].TheString
    

    Mostrando que usou tentativas . Mais informações sobre isso estão na seção de estatísticas de resumo de string logo acima aqui .

    No entanto, não é o mesmo que sua consulta original. Como a primeira instância de _agora é considerada sempre o terceiro caractere, em vez de ser encontrada dinamicamente.

    Se essa suposição estiver codificada em sua consulta original

     WHERE SUBSTRING(TheString, 1, 3) = 'ZZ_'
    

    O método de estimativa muda para CSelCalcHistogramComparison(INTERVAL)e as linhas estimadas tornam-se precisas.

    É capaz de converter isso em um intervalo

    WHERE TheString >=  'ZZ_' AND TheString < ???
    

    e use o histograma para estimar o número de linhas com valores nesse intervalo.

    No entanto, isso se aplica apenas à estimativa de cardinalidade. LIKEé preferível, pois pode usar uma busca de intervalo em tempo de execução. SUBSTRING(TheString, 1, 3)ou LEFT(TheString, 3)não pode.

    • 8

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