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 / user-9643

Justin Grant's questions

Martin Hope
Justin Grant
Asked: 2018-01-11 19:25:27 +0800 CST

A junção de hash entre as tabelas mestre/detalhe produz uma estimativa de cardinalidade muito baixa

  • 9

Ao unir uma tabela mestra a uma tabela de detalhes, como posso incentivar o SQL Server 2014 a usar a estimativa de cardinalidade da tabela maior (detalhe) como a estimativa de cardinalidade da saída da junção?

Por exemplo, ao unir 10 mil linhas mestras a 100 mil linhas de detalhes, quero que o SQL Server estime a associação em 100 mil linhas -- o mesmo que o número estimado de linhas de detalhes. Como devo estruturar minhas consultas e/ou tabelas e/ou índices para ajudar o estimador do SQL Server a aproveitar o fato de que cada linha de detalhes sempre tem uma linha mestra correspondente? (O que significa que uma junção entre eles nunca deve reduzir a estimativa de cardinalidade.)

Aqui estão mais detalhes. Nosso banco de dados possui um par de tabelas mestre/detalhe: VisitTargetpossui uma linha para cada transação de vendas e VisitSalepossui uma linha para cada produto em cada transação. É um relacionamento de um para muitos: uma linha VisitTarget para uma média de 10 linhas VisitSale.

As tabelas ficam assim: (estou simplificando apenas as colunas relevantes para esta questão)

-- "master" table
CREATE TABLE VisitTarget
(
  VisitTargetId int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
  SaleDate date NOT NULL,
  StoreId int NOT NULL
  -- other columns omitted for clarity  
);
-- covering index for date-scoped queries
CREATE NONCLUSTERED INDEX IX_VisitTarget_SaleDate 
    ON VisitTarget (SaleDate) INCLUDE (StoreId /*, ...more columns */);

-- "detail" table
CREATE TABLE VisitSale
(
  VisitSaleId int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
  VisitTargetId int NOT NULL,
  SaleDate date NOT NULL, -- denormalized; copied from VisitTarget
  StoreId int NOT NULL, -- denormalized; copied from VisitTarget
  ItemId int NOT NULL,
  SaleQty int NOT NULL,
  SalePrice decimal(9,2) NOT NULL
  -- other columns omitted for clarity  
);
-- covering index for date-scoped queries
CREATE NONCLUSTERED INDEX IX_VisitSale_SaleDate 
  ON VisitSale (SaleDate)
  INCLUDE (VisitTargetId, StoreId, ItemId, SaleQty, TotalSalePrice decimal(9,2) /*, ...more columns */
);
ALTER TABLE VisitSale 
  WITH CHECK ADD CONSTRAINT FK_VisitSale_VisitTargetId 
  FOREIGN KEY (VisitTargetId)
  REFERENCES VisitTarget (VisitTargetId);
ALTER TABLE VisitSale
  CHECK CONSTRAINT FK_VisitSale_VisitTargetId;

Por motivos de desempenho, desnormalizamos parcialmente copiando as colunas de filtragem mais comuns (por exemplo SaleDate, ) da tabela mestre para as linhas de cada tabela de detalhes e, em seguida, adicionamos índices de cobertura em ambas as tabelas para oferecer melhor suporte a consultas filtradas por data. Isso funciona muito bem para reduzir a E/S ao executar consultas filtradas por data, mas acho que essa abordagem está causando problemas de estimativa de cardinalidade ao unir as tabelas mestre e de detalhes.

Quando juntamos essas duas tabelas, as consultas ficam assim:

SELECT vt.StoreId, vt.SomeOtherColumn, Sales = sum(vs.SalePrice*vs.SaleQty)
FROM VisitTarget vt 
    JOIN VisitSale vs on vt.VisitTargetId = vs.VisitTargetId
WHERE
    vs.SaleDate BETWEEN '20170101' and '20171231'
    and vt.SaleDate BETWEEN '20170101' and '20171231'
    -- more filtering goes here, e.g. by store, by product, etc. 

O filtro de data na tabela de detalhes ( VisitSale) é redundante. Ele está lá para habilitar a E/S sequencial (também conhecido como operador de busca de índice) na tabela de detalhes para consultas filtradas por um intervalo de datas.

O plano para esses tipos de consultas é assim:

insira a descrição da imagem aqui

Um plano real de uma consulta com o mesmo problema pode ser encontrado aqui .

Como você pode ver, a estimativa de cardinalidade para a junção (a dica de ferramenta no canto inferior esquerdo da imagem) é 4x mais baixa: 2,1 M reais versus 0,5 M estimados. Isso causa problemas de desempenho (por exemplo, derramamento para tempdb), especialmente quando essa consulta é uma subconsulta usada em uma consulta mais complexa.

Mas as estimativas de contagem de linhas para cada ramificação da junção estão próximas das contagens de linhas reais. A metade superior da junção é 100K reais versus 164K estimados. A metade inferior da junção tem 2,1 milhões de linhas reais versus 3,7 milhões estimados. A distribuição de hash bucket também parece boa. Essas observações me sugerem que as estatísticas estão corretas para cada tabela e que o problema é a estimativa da cardinalidade da junção.

No começo eu pensei que o problema era o SQL Server esperando que as colunas SaleDate em cada tabela fossem independentes, enquanto na verdade elas eram idênticas. Então, tentei adicionar uma comparação de igualdade para as datas de venda à condição de junção ou à cláusula WHERE, por exemplo

ON vt.VisitTargetId = vs.VisitTargetId and vt.SaleDate = vs.SaleDate

ou

WHERE vt.SaleDate = vs.SaleDate

Isso não funcionou. Isso até piorou as estimativas de cardinalidade! Portanto, o SQL Server não está usando essa dica de igualdade ou outra coisa é a causa raiz do problema.

Tem alguma ideia de como solucionar problemas e, esperançosamente, corrigir esse problema de estimativa de cardinalidade? Meu objetivo é que a cardinalidade da junção mestre/detalhe seja estimada da mesma forma que a estimativa para a entrada maior ("tabela de detalhes") da junção.

Se for importante, estamos executando o SQL Server 2014 Enterprise SP2 CU8 build 12.0.5557.0 no Windows Server. Não há sinalizadores de rastreamento habilitados. O nível de compatibilidade do banco de dados é SQL Server 2014. Vemos o mesmo comportamento em vários SQL Servers diferentes, portanto, parece improvável que seja um problema específico do servidor.

Há uma otimização no Estimador de cardinalidade do SQL Server 2014 que é exatamente o comportamento que estou procurando:

O novo CE, no entanto, usa um algoritmo mais simples que pressupõe que há uma associação de junção um-para-muitos entre uma tabela grande e uma tabela pequena. Isso pressupõe que cada linha na tabela grande corresponde exatamente a uma linha na tabela pequena. Esse algoritmo retorna o tamanho estimado da entrada maior como a cardinalidade de junção.

Idealmente, eu poderia obter esse comportamento, onde a estimativa de cardinalidade para a junção seria a mesma que a estimativa para a tabela grande, mesmo que minha tabela "pequena" ainda retorne mais de 100 mil linhas!

sql-server sql-server-2014
  • 1 respostas
  • 741 Views
Martin Hope
Justin Grant
Asked: 2017-11-08 21:38:57 +0800 CST

A estratégia de preenchimento do SQL Server é a mesma para tempdb de vários arquivos e grupos de arquivos de vários arquivos (não tempdb)?

  • 1

A E/S do tempdb de uma única consulta será dividida em vários arquivos tempdb? (supondo que o tempdb esteja configurado para usar vários arquivos, é claro!)

Para bancos de dados não tempdb, o MDSN parece dizer que sim, os dados recém-adicionados serão espalhados por vários arquivos em um grupo de arquivos:

Os grupos de arquivos usam uma estratégia de preenchimento proporcional em todos os arquivos dentro de cada grupo de arquivos. À medida que os dados são gravados no grupo de arquivos, o Mecanismo de Banco de Dados do SQL Server grava uma quantidade proporcional ao espaço livre no arquivo para cada arquivo dentro do grupo de arquivos, em vez de gravar todos os dados no primeiro arquivo até ficar cheio. Em seguida, ele grava no próximo arquivo. Por exemplo, se o arquivo f1 tiver 100 MB livres e o arquivo f2 tiver 200 MB livres, uma extensão será alocada do arquivo f1, duas extensões do arquivo f2 e assim por diante. Desta forma, ambos os arquivos ficam cheios aproximadamente ao mesmo tempo, e a distribuição simples é alcançada.

Essa mesma estratégia de preenchimento se aplica ao tempdb?

E essa resposta depende do tipo de consulta, por exemplo, paralela versus não paralela? Ou a resposta é diferente com base no tipo de E/S de tempdb, por exemplo, para tempables que crio versus uso de tempdb pelo mecanismo de banco de dados para tabelas de trabalho ou derramamento?

sql-server sql-server-2014
  • 1 respostas
  • 261 Views
Martin Hope
Justin Grant
Asked: 2015-06-29 15:06:02 +0800 CST

concatenando colunas de vários conjuntos de resultados de 1 linha não relacionados

  • 3

Suponha que eu tenha essas duas consultas no SQL Server 2014, ambas retornando uma linha de tabelas não relacionadas:

SELECT SUM(A) A, SUM(B) B FROM X
SELECT SUM(C) C, SUM(D) D FROM Y

Gostaria de combinar essas consultas em um único conjunto de resultados que contém arquivos A, B, C, D.

Qual é uma boa maneira de fazer isso em uma única consulta, em oposição a soluções de várias consultas, como selecionar os resultados dentro e fora de variáveis ​​escalares?

sql-server t-sql
  • 2 respostas
  • 1120 Views
Martin Hope
Justin Grant
Asked: 2012-10-09 16:27:37 +0800 CST

estratégia de manutenção de índice se poucos pontos de inserção relativos ao número de linhas

  • 4

No SQL Server 2008 R2, tenho um índice de cobertura não clusterizado em várias tabelas com mais de 100 milhões de linhas. A tabela tem alguns milhares de "pontos de inserção" onde todas as novas inserções acontecem. Isso significa que, independentemente do fator de preenchimento, terminarei rapidamente com divisões de página e fragmentação em cada ponto de inserção e nenhuma fragmentação ou divisão em nenhum outro lugar da tabela. Infelizmente, as consultas sempre incluem novas linhas e, portanto, áreas fragmentadas do índice.

  • o que acontece quando há uma divisão de página, mas as inserções continuam sequencialmente após a divisão? Existe uma maneira de dizer ao SQL Server para fazer a divisão com muito espaço extra para inserções subsequentes, sem desperdiçar espaço em páginas existentes com um grande fator de preenchimento que, para a maioria das páginas, nunca será preenchido?
  • quais são as boas estratégias de manutenção de índice a serem usadas para índices como este?
  • existe uma boa maneira automatizada de identificar tabelas como esta em que a fragmentação é severa, mas não uniforme? Essas tabelas não aparecem com mais de 5% de fragmentação geral.
  • há alterações de esquema de índice que devo considerar?

Aqui estão mais informações sobre o problema. Todos os índices se parecem com este padrão (simplificado para maior clareza abaixo):

CREATE TABLE Foo (
    id int identity(1,1) PRIMARY KEY CLUSTERED, 
    foreign_key int, 
    log_time datetime, 
    ...)     
CREATE NONCLUSTERED INDEX on Foo (foreign_key, log_time) INCLUDE (...)

As consultas nesta tabela estão sempre neste formato:

WHERE log_time > getdate()-70 AND foreign_key IN (select ...)

Outros fatos:

  • existem cerca de 5.000 valores de chave estrangeira, cada um com 10.000 linhas para cada um.
  • o tamanho médio da linha é de 55 bytes, o que significa cerca de 150 linhas por página
  • o INfiltro geralmente inclui 10%-50% das foreign_keylinhas de valores e o filtro de data inclui 20%-40% das linhas. A média é de cerca de 15% do total de linhas selecionadas.
  • o índice é um índice de cobertura para as consultas, portanto, nenhum acesso de índice clusterizado é necessário.
sql-server sql-server-2008-r2
  • 2 respostas
  • 155 Views
Martin Hope
Justin Grant
Asked: 2012-07-10 11:15:22 +0800 CST

Como o SQL Server sabe que os predicados estão correlacionados?

  • 15

Ao diagnosticar consultas do SQL Server 2008 R2 com estimativa de cardinalidade ruim (apesar da indexação simples, estatísticas atualizadas etc. ) que contém predicados AND correlacionados no SQL Server 2008 ou no SQL Server 2008 R2 ou no SQL Server 2012

Posso adivinhar o que o artigo da KB quer dizer com "correlacionado", por exemplo, predicado nº 2 e predicado nº 1, em grande parte, visam as mesmas linhas.

Mas não sei como o SQL Server sabe dessas correlações. Uma tabela precisa de um índice de várias colunas contendo colunas de ambos os predicados? O SQL usa estatísticas para verificar se os valores de uma coluna estão correlacionados com outra? Ou algum outro método é usado?

Estou perguntando isso por dois motivos:

  1. para determinar quais das minhas tabelas e consultas podem ser melhoradas usando este hotfix
  2. para saber o que devo fazer na indexação, estatísticas, etc. para afetar #1
sql-server sql-server-2008-r2
  • 1 respostas
  • 1708 Views
Martin Hope
Justin Grant
Asked: 2012-06-26 02:57:35 +0800 CST

leituras lógicas vs. contagem de varreduras

  • 8

Estou unindo uma tabela pequena (1.000 linhas) a uma tabela grande (8 milhões de linhas) no SQL Server 2008. A junção usa um índice de cobertura não clusterizado na tabela grande e pode produzir três planos de consulta possíveis. Estou tentando descobrir qual plano é melhor, mas também quero generalizar esse conhecimento para que, da próxima vez, possa saber melhor qual heurística usar ao examinar as estatísticas de E/S do SQL.

O plano nº 1 é uma junção de loop e emite estatísticas para a tabela grande como esta:

Scan count 2582, logical reads 35686, physical reads 1041, read-ahead reads 23052

O plano nº 2 é uma junção de mesclagem e emite estatísticas como esta:

Scan count 1, logical reads 59034, physical reads 49, read-ahead reads 59004

O plano #3 é um hash join e emite estatísticas como esta:

Scan count 3, logical reads 59011, physical reads 5, read-ahead reads 59010

O índice de cobertura é ordenado por (ID, Date). A consulta retorna dados para cerca de 50% dos IDs e, para cada ID, retorna uma parte contígua dos dados dos 3 meses mais recentes, que geralmente é cerca de 1/4 ou as linhas de cada ID. A consulta retorna cerca de 1/8 do total de linhas no índice. Em outras palavras, a consulta é esparsa, mas consistente.

Minha suposição é que o plano nº 1 é péssimo para essa carga de trabalho, porque mover a cabeça do disco cerca de 2.500 vezes (ou até 1.041 vezes) é muito mais caro do que uma varredura de disco sequencial. Também suponho que os números 3 e 2 tenham padrões de E/S semelhantes e sequenciais (e, portanto, mais eficientes).

Mas existe um caso em que o plano nº 1 é realmente o melhor, em que "melhor" significa menos impacto no subsistema de E/S e menos impacto em outras consultas executadas simultaneamente?

Ou realmente depende de muitas variáveis, como o tipo de subsistema de disco que tenho, fragmentação de índice, etc. Se "depender", existem regras práticas para abordar o problema?

sql-server sql-server-2008
  • 3 respostas
  • 6436 Views

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