É possível forçar o otimizador a eliminar tabelas irrelevantes nessa exibição particionada?

22

Estou testando arquiteturas diferentes para tabelas grandes e uma sugestão que vi é usar uma exibição particionada, na qual uma tabela grande é dividida em uma série de tabelas "particionadas" menores.

1 , 2 , 3 , 4

Ao testar essa abordagem, descobri algo que não faz muito sentido para mim. Quando filtro a "coluna de particionamento" na exibição de fatos, o otimizador procura apenas nas tabelas relevantes. Além disso, se eu filtrar essa coluna na tabela de dimensões, o otimizador eliminará as tabelas desnecessárias.

No entanto, se eu filtrar algum outro aspecto da dimensão, o otimizador procurará no PK / CI de cada tabela base.

Aqui estão as consultas em questão:

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where o.ObservationDateKey >= 20000101
    and o.ObservationDateKey <= 20051231
group by od.[Year];

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where od.DateKey >= 20000101
    and od.DateKey <= 20051231
group by od.[Year];

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where od.[Year] >= 2000 and od.[Year] < 2006
group by od.[Year];

filtro de fato na chave

filtro fraco na chave

filtro escuro no aspecto

Aqui está um link para a sessão do SQL Sentry Plan Explorer.

Estou trabalhando para particionar a tabela maior para ver se a eliminação da partição responde de maneira semelhante.

Eu obtenho eliminação de partição para a consulta (simples) que filtra um aspecto da dimensão.

Enquanto isso, aqui está uma cópia apenas do stats do banco de dados:

https://gist.github.com/swasheck/9a22bf8a580995d3b2aa

O "antigo" estimador de cardinalidade recebe um plano mais barato, mas isso se deve às estimativas mais baixas de cardinalidade em cada uma das buscas (desnecessárias) do índice.

Gostaria de saber se existe uma maneira de fazer com que o otimizador use a coluna-chave ao filtrar por outro aspecto da dimensão, para que ele possa eliminar buscas em tabelas irrelevantes.

Versão do SQL Server:

Microsoft SQL Server 2014 - 12.0.2000.8 (X64) 
    Feb 20 2014 20:04:26 
    Copyright (c) Microsoft Corporation
    Developer Edition (64-bit) on Windows NT 6.3 <X64> (Build 9600: ) (Hypervisor)
swasheck
fonte
Apenas um FYI .. o último fluxo de status está corrompidoCREATE STATISTICS [_WA_Sys_00000008_2FCF1A8A] ON [dbo].[Observation_2010]([StationStateCode]) WITH STATS_STREAM = 0x01000000010000000000000000000000D4531EDB00000000D5080000000000009508000000000000AF030000AF000000020000000000000008D000340000000007000000E65DE0007DA5000076F9780000000000867704000000000000000000ABAAAA3C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Kin Shah
Parece que o script para o banco de dados somente estatísticas está truncado. Tentei clicar em "visualizar o arquivo completo" e fazer o download do zip, mas de qualquer forma não tenho estatísticas para a ObservationDatestabela. Não estou conseguindo o mesmo plano que Paul, mesmo com o 4199, e acho que é por isso.
Geoff Patterson
@GeoffPatterson funciona para mim. você clicou no link para o arquivo bruto? gist.githubusercontent.com/swasheck/9a22bf8a580995d3b2aa/raw/… no entanto, como Kin observou, o último fluxo de estatísticas está corrompido: /
swasheck
Cliquei no link do arquivo bruto. O script funciona (exceto o problema que Kin notou), mas não contém lógica para criar estatísticas ObservationDates. Acabei rodando UPDATE STATISTICS ObservationDates WITH ROWCOUNT = 10000manualmente para obter o plano que Paul demonstrou.
Geoff Patterson
ímpar. criando um novo banco de dados e executando esse script, tenho objetos de estatísticas (bem, são índices), ObservationDatesentão não tenho certeza do que está acontecendo com isso. Além disso, também não sou capaz de obter o plano que Paulo gerou. vou tentar a atualização para ver.
swasheck 6/01/16

Respostas:

10

Ative o sinalizador de rastreamento 4199.

Eu também tive que emitir:

UPDATE STATISTICS dbo.ObservationDates 
WITH ROWCOUNT = 73049;

para obter os planos mostrados abaixo. As estatísticas desta tabela estavam ausentes no upload. A figura 73.049 veio das informações de Cardinalidade da tabela no anexo do Explorador de plano. Usei o SQL Server 2014 SP1 CU4 (compilação 12.0.4436) com dois processadores lógicos, memória máxima definida como 2048 MB e nenhum sinalizador de rastreamento além do 4199.

Você deve obter um plano de execução que inclua a eliminação dinâmica de partições:

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where 
    od.[Year] >= 2000 and od.[Year] < 2006
group by 
    od.[Year]
option (querytraceon 4199);

Fragmento do plano:

Fragmento de plano

Isso pode parecer pior, mas os filtros são todos filtros de inicialização . Um exemplo de predicado é:

Propriedades do filtro

Por iteração do loop, o predicado de inicialização é testado e somente se retornar verdadeiro é que a Busca de Índice Clusterizado abaixo dele é executada. Portanto, eliminação dinâmica da partição.

Esta é, talvez, não muito eficiente como eliminação de estática, especialmente se o plano é paralelo.

Pode ser necessário tentar dicas como MAXDOP 1, FAST 1ou FORCESEEKna exibição, para obter o mesmo plano. As opções de custo do otimizador com visualizações particionadas (como tabelas particionadas) podem ser complicadas.

O ponto é que você precisa de um plano que inclua filtros de inicialização para obter a eliminação dinâmica de partições com visualizações particionadas.


Consultas com USE PLANdicas incorporadas : (via gist.github.com):

Paul White diz que a GoFundMonica
fonte
1
Ótima informação, obrigado Paul! Fiquei me perguntando depois que escrevi minha resposta por que não existe uma maneira de o SQL Server fazer esse tipo de eliminação. Acontece que há, eu simplesmente não tinha visto isso antes!
Geoff Patterson
6

Minha observação sempre foi que você deve especificar o valor (ou intervalo de valores) para a coluna da partição explicitamente na consulta, a fim de obter a "eliminação da tabela" em uma exibição particionada. Isso se baseia na experiência do uso de modos de exibição particionados na produção do SQL Server 2000 ao SQL Server 2014.

O SQL Server não tem um conceito de operador de junção de loop, no qual o mecanismo pode direcionar dinamicamente a busca diretamente para a tabela apropriada no lado interno do loop, com base no valor da linha no lado externo do loop. No entanto, como a resposta de Paul explica , existe a possibilidade de um plano com filtros de inicialização para ignorar dinamicamente tabelas irrelevantes no lado interno do loop em tempo constante (ao contrário de logarítmico realizando a busca).

Observe que, para tabelas particionadas, no entanto, esse tipo de busca (para uma partição específica) é suportada.

Se você está decidido a usar visualizações particionadas, outra opção é dividir sua consulta em várias consultas, como:

-- Gather than the min/max values for the partition column
DECLARE @minDateKey INT,
        @maxDateKey INT
SELECT @minDateKey = MIN(DateKey),
        @maxDateKey = MAX(DateKey)
FROM dbo.ObservationDates od
WHERE od.[Year] >= 2000 and od.[Year] < 2006

-- Since I have a stats-only copy of the database, simulate having run the query above
-- (You can comment this out since you have the actual data.)
SELECT @minDateKey = 20000101, @maxDateKey = 20051231

-- Adjust the query to use the min/max values of the partition column
-- rather than filtering on a different column in the dimension table
select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
WHERE od.DateKey >= @minDateKey AND od.DateKey <= @maxDateKey
group by od.[Year]
-- Must use OPTION RECOMPILE; otherwise the plan will touch all tables because it
-- must do so in order to be valid for all values of the parameters!
OPTION (RECOMPILE)

Isso produz o seguinte plano. Agora existe uma consulta extra que atinge a tabela de dimensões, mas a consulta sobre a tabela de fatos (presumivelmente muito maior) é otimizada.

insira a descrição da imagem aqui

Geoff Patterson
fonte
O mesmo efeito seria alcançado se você incorporasse a primeira consulta na segunda sem recorrer a variáveis?
Andriy M
@AndriyM Se estou entendendo corretamente, a resposta é não, o mesmo efeito não será alcançado e o plano de consulta tocará em todas as tabelas na exibição particionada se você tentar combinar as duas consultas. Se você executasse a primeira consulta, cole os valores 20000101e, em 20051231vez das variáveis ​​(ou faça algo semelhante por meio de duas consultas separadas em seu aplicativo), sim, o mesmo efeito seria alcançado sem o uso das variáveis.
Geoff Patterson