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 / 84577
Accepted
Shaul Behr
Shaul Behr
Asked: 2014-12-09 01:05:51 +0800 CST2014-12-09 01:05:51 +0800 CST 2014-12-09 01:05:51 +0800 CST

Otimização de índice em uma exibição usando uma junção externa completa

  • 772

Estrutura da tabela:

Foo             FooChild                Bar
---             --------                ---
ID              ID                      ID
Date            FooID                   Date
GroupID         UserID                  UserID
Notes           Amount                  GroupID
                                        IsComplete
  • Footem um índice único em Date+GroupID
  • FooChildtem um FK para Foo e um índice exclusivo em FooID+ UserID, que incluiAmount
  • Bartem um índice exclusivo em ++ Date, que incluiUserIDGroupIDIsComplete

Agora preciso criar um relatório mostrando a soma de todos os valores de FooChild junto com a contagem de barras completas para qualquer intervalo de datas. Os usuários também querem poder ver as estatísticas por grupo ou por usuário. Este parece ser um ótimo lugar para escrever uma visão:

create view vFooBar as
select f.Date, f.GroupID, fc.UserID, fc.Amount, b.IsComplete
from Foo f join FooChild fc on fc.FooID = f.ID
left join Bar b on f.Date = b.Date and f.GroupID = b.GroupID and fc.UserID = b.UserID
union
select b.Date, b.GroupID, b.UserID, x.Amount, b.IsComplete
from Bar b left join 
    (select f.Date, f.GroupID, fc.UserID, fc.Amount
    from Foo f join FooChild fc on fc.FooID = f.ID) x
on x.Date = b.Date and x.GroupID = b.GroupID and x.UserID = b.UserID

( É por isso que escrevi a visão dessa maneira.)

Agora posso facilmente escrever consultas como esta:

select UserID, sum(Amount) FooAmount, sum(cast(IsCompleted as int)) CompletedBars
from vFooBar
where Date between @fromDate and @toDate
group by UserID

Mas há um obstáculo aqui. Assim que o intervalo de datas começa a ficar relativamente grande, o plano de execução fica todo em forma de pêra. Ele usa o índice de data em Foo, mas em vez de usar o FooIDíndice em FooChild, ele faz uma varredura de índice clusterizado e, em seguida, uma correspondência de hash FooIDpara se juntar aos resultados de Foo. E faz isso duas vezes no plano geral; Eu estou supondo uma vez para cada agregado. E isso realmente dói.

Entendo que usar o índice que criei FooChildpode não ser eficiente, pois os valores de FooIDpara uma determinada data podem ser discretos, embora normalmente sejam inseridos aproximadamente na mesma ordem.

Eu poderia desnormalizar e adicionar Datee GroupIDà tabela FooChild, indexar essas colunas e tenho certeza de que isso melhoraria muito o desempenho. Mas simplesmente não parece certo.

Alguma outra ideia?

index sql-server-2012
  • 1 1 respostas
  • 169 Views

1 respostas

  • Voted
  1. Best Answer
    Paul White
    2014-12-09T03:23:31+08:002014-12-09T03:23:31+08:00

    O otimizador faz escolhas com base em estimativas de custo. O modelo de custo é genérico e nem sempre pode escolher planos ideais para seu hardware específico, e suas suposições podem nem sempre ser válidas para suas circunstâncias.

    Nesse caso, o otimizador avalia uma junção de hash como a opção mais barata em relação a loops aninhados quando o número estimado de linhas a serem unidas é grande. Se você tiver certeza de que uma junção de loops aninhados sempre será preferível a uma junção de hash, considere (e teste!) Forçar uma busca em vez de uma varredura da FooChildtabela na exibição:

    SELECT 
        f.TheDate, 
        f.GroupID, 
        fc.UserID, 
        fc.Amount, 
        b.IsComplete
    FROM dbo.Foo AS f 
    JOIN dbo.FooChild AS fc WITH (FORCESEEK) -- New hint
        ON fc.FooID = f.ID
    LEFT JOIN dbo.Bar AS b 
        ON f.TheDate = b.TheDate 
        AND f.GroupID = b.GroupID 
        AND fc.UserID = b.UserID
    UNION
    SELECT 
        b.TheDate, 
        b.GroupID, 
        b.UserID, 
        x.Amount, 
        b.IsComplete
    FROM dbo.Bar AS b 
    LEFT JOIN 
    (
        SELECT 
            f.TheDate, 
            f.GroupID, 
            fc.UserID, 
            fc.Amount
        FROM dbo.Foo AS f 
        JOIN dbo.FooChild AS fc WITH (FORCESEEK) -- New hint
            ON fc.FooID = f.ID
    ) AS x
        ON x.TheDate = b.TheDate 
        AND x.GroupID = b.GroupID 
        AND x.UserID = b.UserID;
    

    Observação: embora essa transformação da junção completa original seja válida, dadas as restrições de exclusividade atuais em suas tabelas, revise a resposta à sua pergunta anterior e considere reescrever a junção completa conforme sugerido em minha edição.

    • 3

relate perguntas

  • Como criar várias entradas no índice com base nos campos de uma linha?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quanto "Padding" coloco em meus índices?

  • 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