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 / 330247
Accepted
J. Mini
J. Mini
Asked: 2023-08-13 20:12:28 +0800 CST2023-08-13 20:12:28 +0800 CST 2023-08-13 20:12:28 +0800 CST

O PERCENTILE_CONT ainda oferece um desempenho terrível ao calcular medianas nas versões 2022 do SQL Server?

  • 772

Atualmente, estou lendo um livro do SQL Server 2014. Ele, como todas as outras fontes online que encontrei, informa que é PERCENTILE_CONTuma maneira muito lenta de calcular medianas e não mostra o plano de execução supostamente péssimo. Ainda é PERCENTILE_CONTextremamente lento nesta tarefa nas versões recentes (ou seja, 2022 ou posteriores) do SQL Server?

"Extremamente lento" é subjetivo, portanto, mostrar que os planos de execução não mudam entre o SQL Server 2014 e 2022 será suficiente. Eu mesmo verificaria isso, mas o servidor mais novo que tenho está na versão de 2012.

sql-server
  • 2 2 respostas
  • 401 Views

2 respostas

  • Voted
  1. Best Answer
    Martin Smith
    2023-08-13T22:27:35+08:002023-08-13T22:27:35+08:00

    Presumo que uma das fontes online a que você se refere seja Qual é a maneira mais rápida de calcular a mediana?

    "2012_A" e "2012_B" abaixo referem-se às consultas desse artigo.

    Usando dados de teste semelhantes...

    CREATE TABLE dbo.obj(id INT IDENTITY(1,1), val INT, PRIMARY KEY (val, id));
     
    INSERT dbo.obj(val) 
    SELECT TOP (10000000) CRYPT_GEN_RANDOM(3) as val
    FROM sys.all_columns AS c 
    CROSS JOIN sys.all_objects AS o
    CROSS JOIN sys.all_objects AS o2
    

    2012_A com nível de compatibilidade 2014

    Tentar a mesma instância do SQL Server 2022 como os testes subsequentes, mas com o nível de compatibilidade de 120 (SQL Server 2014) levou 1 minuto e 56 segundos

    --Table 'Worktable'. Scan count 6, logical reads 60127770, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.
    --Table 'obj'. Scan count 1, logical reads 21109, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.
    --CPU time = 82000 ms,  elapsed time = 116489 ms.
    SELECT TOP 1 PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY val) OVER () 
    FROM dbo.obj
    OPTION (USE hint('QUERY_OPTIMIZER_COMPATIBILITY_LEVEL_120'))
    

    plano 120

    2012_A em 2022

    No SQL Server 2019+, o plano de execução agora pode usar agregações janeladas em modo de lote e isso foi consideravelmente mais rápido que o esforço anterior, com um tempo decorrido de 7,5 segundos, mas ainda é mais lento que o método mais rápido proposto naquele artigo (talvez atualize este método de "terrível" para "ruim") .

    --Table 'obj'. Scan count 1, logical reads 21109, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.
    --Table 'Worktable'. Scan count 2, logical reads 918272, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.
    -- CPU time = 4407 ms,  elapsed time = 7525 ms.
    SELECT TOP 1 PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY val) OVER () 
    FROM dbo.obj;
    

    insira a descrição da imagem aqui

    PERCENTILE_CONTé implementado como uma função analítica e todas as 10.000.000 linhas de origem são colocadas em spool no Window Aggregate à direita para que possam ter o resultado adicionado a elas assim que for calculado. Isso é inerentemente intensivo em recursos.

    PERCENTILE_CONTnão pôde ser implementado como um agregado de streaming porque você precisa ler todo o stream para obter a contagem e, assim, conhecer as linhas de seu interesse.

    O método "vencedor" do artigo SQL Performance ainda vence em 2022 - com um tempo decorrido de cerca de 1 segundo.

    2012_B

    --Table 'obj'. Scan count 9, logical reads 21499, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.
    --Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.
    --CPU time = 251 ms,  elapsed time = 133 ms.
    DECLARE @c BIGINT = (SELECT COUNT(*) FROM dbo.obj);
     
    
    --Table 'obj'. Scan count 1, logical reads 10567, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.
    --CPU time = 313 ms,  elapsed time = 859 ms.
    SELECT  AVG(1.0 * val)
    FROM (
        SELECT val FROM dbo.obj
         ORDER BY val
         OFFSET (@c - 1) / 2 ROWS
         FETCH NEXT 1 + (1 - @c % 2) ROWS ONLY
    ) AS x;
    

    insira a descrição da imagem aqui

    Resultado Aproximado

    O SQL Server 2022 inclui uma nova função agregada APPROX_PERCENTILE_CONT. Como esta é uma função agregada, não requer uma OVERcláusula - ou o que TOP 1adicionei à PERCENTILE_CONTconsulta acima

    --Table 'obj'. Scan count 9, logical reads 21499, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.
    --Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0.
    --CPU time = 4983 ms,  elapsed time = 881 ms.
    select APPROX_PERCENTILE_CONT (0.5) WITHIN GROUP (ORDER BY val)
    FROM dbo.obj
    

    insira a descrição da imagem aqui

    Embora o tempo decorrido tenha sido competitivo com 2012_B, no geral, ele usou muito mais tempo de CPU e, além disso, retorna apenas uma aproximação do resultado correto - portanto, para este teste, eu ainda preferiria 2012_B

    • 4
  2. Paul White
    2023-08-14T18:51:48+08:002023-08-14T18:51:48+08:00

    Ainda é PERCENTILE_CONTextremamente lento nesta tarefa nas versões recentes (ou seja, 2022 ou posteriores) do SQL Server?

    É sim. Nenhuma das facilidades de percentil é especificamente otimizada para o caso mediano. A natureza geral da implementação (para qualquer percentil, não apenas 0,5) significa que ela é mais flexível, mas menos eficiente do que poderia ser uma função ou agregação de janela somente mediana específica.


    Usando os dados de teste de Martin, descobri que 2012_B foi executado em cerca de 400ms :

    DECLARE @c BIGINT = (SELECT COUNT(*) FROM dbo.obj);
    
    DECLARE @Start datetime2 = SYSUTCDATETIME();
    
    SELECT  AVG(1.0 * val)
    FROM (
        SELECT val FROM dbo.obj
         ORDER BY val
         OFFSET (@c - 1) / 2 ROWS
         FETCH NEXT 1 + (1 - @c % 2) ROWS ONLY
    ) AS x;
    
    SELECT [2012_B] = DATEDIFF(MILLISECOND, @Start, SYSUTCDATETIME());
    

    Isso pode ser aprimorado no nível de compatibilidade 150 (SQL Server 2019) ou posterior usando o modo de lote no Rowstore (BMOR) por meio de uma expressão diferente do mesmo algoritmo básico:

    DECLARE @c bigint = (SELECT COUNT_BIG(*) FROM dbo.obj);
    
    DECLARE @Start datetime2 = SYSUTCDATETIME();
    
    SELECT 
        IIF
        (
            @c % 2 = 1, 
            SUM(SQ1.val), 
            SUM(SQ1.val) * 5e-1
        ) 
    FROM 
    (
        SELECT TOP (1 + (1 - @c % 2))
            A.val
        FROM 
        (
            SELECT 
                O.val, 
                rn = ROW_NUMBER() OVER (ORDER BY O.val ASC)
            FROM dbo.obj AS O
        ) AS A
        WHERE
            A.rn >= ((@c - 1) / 2)
        ORDER BY
            A.rn
    ) AS SQ1;
    
    SELECT BMOR = DATEDIFF(MILLISECOND, @Start, SYSUTCDATETIME());
    

    Essa implementação é executada em cerca de 275 ms , com todas as operações caras usando o processamento em lote (destaque em azul).

    plano BMOR

    Observação BMOR requer Enterprise Edition ou equivalente.

    • 1

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