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 / 316232
Accepted
John
John
Asked: 2022-08-31 07:34:38 +0800 CST2022-08-31 07:34:38 +0800 CST 2022-08-31 07:34:38 +0800 CST

O índice procura uma chave específica de várias colunas e, em seguida, obtém algumas linhas em ordem lexicográfica

  • 772

Considere a seguinte tabela de amostra com um índice de várias colunas:

create table BigNumbers (
    col1 tinyint not null,
    col2 tinyint not null,
    col3 tinyint not null,

    index IX_BigNumbers clustered (col1, col2, col3)
)

DECLARE @n INT = 100;

DECLARE @x1 INT = 0;
DECLARE @x2 INT = 0;
DECLARE @x3 INT = 0;

SET NOCOUNT ON;

WHILE @x3 <= @n BEGIN
    SET @x2 = 0;
    WHILE @x2 <= @n BEGIN
        SET @x1 = 0;
        WHILE @x1 <= @n BEGIN
            insert into BigNumbers values (@x1, @x2, @x3);
            SET @x1 = @x1 + 1;
        END;
        SET @x2 = @x2 + 1;
    END;

 SET @x3 = @x3 + 1;
END;

Meu objetivo agora é obter algumas linhas desse índice, começando com uma determinada chave.

O que parece trivial é um pouco complicado, pois não há uma maneira fácil no SQL de expressar a ordem lexicográfica em que o índice está:

DECLARE @x1 INT = 60;
DECLARE @x2 INT = 40;
DECLARE @x3 INT = 98;

select top 5 *
from BigNumbers 
where
  col1 > @x1 or
 (col1 = @x1 and
   (col2 > @x2 or
   (col2 = @x2 and col3 >= @x3)))
order by col1, col2, col3

O resultado correto é:

60  40  98
60  40  99
60  40  100
60  41  0
60  41  1

No entanto, o plano de consulta me diz que isso usa uma verificação de índice.

O índice subjacente deve ser capaz de buscar e retornar as primeiras linhas maiores ou iguais (@x1, @x2, @3)na ordem do índice, mas como não há como no SQL expressar essa intenção facilmente, o planejador de consulta parece incapaz de entender a dica e, em vez disso, faz uma varredura .

Dicas de índice não ajudam e FORCESEEKdá um plano horrendo.

Curiosamente, a seguinte versão de duas colunas funciona:

select top 5 *
from BigNumbers 
where
  col1 = @x1 and
   (col2 > @x2 or
   (col2 = @x2 and col3 >= @x3))
order by col1, col2, col3

Não sei por que isso acontece, mas o plano não apenas usa uma busca, como também relata corretamente ter tocado apenas 5 linhas:

insira a descrição da imagem aqui

Eu gostaria de saber se alguém conhece uma maneira de consultar algumas linhas de um índice maior ou igual a uma determinada tupla de valor com uma busca simples de forma confiável.

Parece estranho que o banco de dados obscureça essa capacidade fundamental sob suas abstrações de nível superior.

Se alguém estiver interessado em saber qual é o problema, estou desenvolvendo uma UI genérica para bancos de dados SQL. O lugar mais óbvio onde você precisa disso é para um botão "carregar mais" onde você deseja continuar mostrando o conteúdo do índice para um determinado ponto de partida. Se isso não for possível em geral, a solução alternativa seria primeiro consultar a correção de todas as colunas, exceto a última, e fazer uma segunda consulta e assim por diante. Seria um pouco de vergonha ter que fazer isso embora.

sql-server index
  • 2 2 respostas
  • 530 Views

2 respostas

  • Voted
  1. Best Answer
    Charlieface
    2022-08-31T12:34:22+08:002022-08-31T12:34:22+08:00

    O que você está se referindo é uma comparação de linha e você a está usando para uma consulta de paginação de conjunto de chaves . Nos SGBDs que o suportam , você pode simplesmente fazer

    where (col1, col2, col3) >= (@x1, @x2, @x3)
    

    No entanto, o SQL Server não oferece suporte a isso. O que ele suporta é uma busca de índice em vários intervalos. Assim, a busca de índice único torna-se duas ou três, mas a ordenação é compreendida e mantida pelo compilador, de modo que atua efetivamente como uma busca única em um intervalo.

    Ele usa isso em vários tipos diferentes de consultas, principalmente INlistas e ORconsultas. Ele também o usa na lógica de comparação de linhas, o que é muito útil ao fazer a Paginação do Conjunto de Chaves.

    No seu caso, não está reconhecendo esse padrão. Parece que isso ocorre porque você está usando lógica booleana aninhada para expressá-la. Ele reconhecerá com sucesso a seguinte lógica, que é exatamente a mesma semanticamente

    where (col1 = @x1 and col2 = @x2 and col3 >= @x3)
     or (col1 = @x1 and col2 > @x2)
     or (col1 > @x1)
    

    plano

    db<>violino

    Exatamente por que ele reconhece um e não o outro não está claro. Talvez alguém com acesso a um depurador e/ou conhecimento das regras do otimizador possa elaborar.

    • 8
  2. Paul White
    2022-09-01T03:10:42+08:002022-09-01T03:10:42+08:00

    Em um mundo perfeito, as pessoas seriam capazes de escrever consultas em qualquer forma logicamente equivalente e o otimizador produziria o mesmo plano de execução ideal em todos os casos.

    Esta não é uma proposta prática - o otimizador tem um tempo limitado para trabalhar e um conhecimento incompleto das possíveis transformações. Por isso, às vezes temos a necessidade de expressar nossa exigência em uma forma escrita específica para obter o melhor resultado.

    O SQL Server faz alguns esforços para padronizar (normalizar) a forma lógica da instrução enviada, mas eles não são exaustivos. Por exemplo, as cláusulas lógicas são transformadas na forma normal de negação (NNF), mas não na forma normal conjuntiva (CNF) ou disjuntiva (DNF). A transformação para NNF é sempre fácil e compacta; nem sempre é assim para CNF ou DNF.

    Isso é uma pena no seu caso, porque o formulário DNF é fácil de derivar e funciona bem com a lógica de correspondência de índice, conforme mostrado em outra resposta :

    DECLARE 
        @x1 tinyint = 60,
        @x2 tinyint = 40,
        @x3 tinyint = 98;
    
    SELECT TOP (5) 
        BN.col1, 
        BN.col2, 
        BN.col3 
    FROM dbo.BigNumbers AS BN
    WHERE 
        (BN.col1 = @x1 AND BN.col2 = @x2 AND BN.col3 >= @x3)
        OR (BN.col1 = @x1 AND BN.col2 > @x2)
        OR (BN.col1 > @x1)
    ORDER BY 
        BN.col1, 
        BN.col2, 
        BN.col3;
    

    Isso produz um TRIVIALplano de execução com três operações de busca separadas dentro da busca de índice clusterizado, executadas sequencialmente (com curto-circuito):

    Plano de busca múltipla

    O ideal, como também já observado, seria o SQL Server implementar construtores de linha, com a lógica expandida conforme necessário para a forma ideal para correspondência de índice. Isso foi solicitado há muito tempo, mas frustrantemente ainda não foi entregue. Por enquanto, precisamos escrever consultas de paginação baseadas em âncoras de uma maneira específica.

    Uma solução um pouco menos eficiente, mas ainda decente, é:

    DECLARE 
        @x1 tinyint = 60,
        @x2 tinyint = 40,
        @x3 tinyint = 98;
    
    SELECT BN.col1, BN.col2, BN.col3 
    FROM dbo.BigNumbers AS BN 
    WHERE BN.col1 = @x1 
    AND BN.col2 = @x2 
    AND BN.col3 >= @x3
    
    UNION ALL 
    
    SELECT BN.col1, BN.col2, BN.col3 
    FROM dbo.BigNumbers AS BN 
    WHERE BN.col1 = @x1 
    AND BN.col2 > @x2
    
    UNION ALL 
    
    SELECT BN.col1, BN.col2, BN.col3 
    FROM dbo.BigNumbers AS BN 
    WHERE BN.col1 > @x1
    
    ORDER BY BN.col1, BN.col2, BN.col3
    OFFSET 0 ROWS 
    FETCH FIRST 5 ROWS ONLY;
    

    Mesclar plano de concatenação

    Este plano tem três buscas únicas, mas cada uma deve produzir pelo menos uma linha para a comparação de concatenação de mesclagem, para que nenhuma possa ser completamente curto-circuitada.

    db<>violino

    • 5

relate perguntas

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Quanto "Padding" coloco em meus índices?

  • Como determinar se um Índice é necessário ou necessário

  • O que significa "índice" em RDBMSs? [fechado]

  • Como criar um índice condicional no MySQL?

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