Eu tenho uma grande tabela de fatos com milhões de linhas chamada MyLargeFactTable e é uma tabela de armazenamento de colunas em cluster.
Também há uma restrição de chave primária composta (colunas customer_id,location_id,order_date).
Eu também tenho uma tabela temporária #my_keys_to_filter_MyLargeFactTable, com as mesmas 3 colunas, e contém alguns milhares de combinações ÚNICAS desses 3 valores de chave.
A consulta a seguir me retorna o conjunto de resultados desejado
...
FROM #my_keys_to_filter_MyLargeFactTable AS t
JOIN dbo.MyLargeFactTable AS m
ON m.customer_id = t.customer_id
AND m.location_id = t.location_id
AND m.order_date = t.order_date
mas noto que o Operador de varredura de índice na tabela de fatos retorna mais linhas do que deveria (cerca de um milhão) e o alimenta em um operador de filtro, o que reduz ainda mais o conjunto de resultados para os poucos milhares de linhas desejados.
O operador Index Scan lê muitas linhas (eles são linhas bastante largas), aumentando a E/S e diminui significativamente toda a consulta.
Meus parâmetros não são sargáveis?
Como eu poderia remover o operador Filter e de alguma forma forçar o operador Index Scan a ler apenas alguns milhares de linhas?
Definições da tabela:
create table #my_keys_to_filter_MyLargeFactTable
(
customer_id varchar(96) not null,
location_id varchar(96) not null,
order_date date not null,
primary key clustered (customer_id,location_id,order_date)
)
create table MyLargeFactTable
(
customer_id varchar(96) not null,
location_id varchar(96) not null,
order_date date not null,
...
lot of wide decimal typed columns, and even large varchars
...
PRIMARY KEY NONCLUSTERED (customer_id,location_id,order_date),
INDEX cci CLUSTERED COLUMNSTORE
)
O operador Filter está aplicando o bitmap criado nas colunas de junção na junção de hash.
Dos três predicados de junção, apenas
order_date
tem um tipo de dados com suporte para empilhamento de bitmap para a varredura de armazenamento de coluna. Se você observar o Predicado na varredura, deverá ver isso como algo como:Os predicados de junção restantes são strings e, portanto, aparecerão no Filtro como parte do teste de bitmap completo:
Empurrar (partes de) o teste de bitmap para a varredura de armazenamento de colunas é uma otimização que está disponível apenas para tipos de dados que podem caber em 64 bits (como
date
no seu exemplo). Observe que o empilhamento de bitmap de junção é diferente do empilhamento de predicado de string (por exemplo, pressionandocustomer_id LIKE '%XYZ%'
).Existem várias maneiras de contornar essa limitação. Reprojetar o esquema de forma que cadeias longas sejam movidas para uma tabela de dimensões e referenciadas usando uma chave inteira é uma opção.
Um pouco menos intrusivo, você pode adicionar um inteiro
checksum
ao armazenamento de colunas (infelizmente não como uma coluna computada persistente) e uma tabela temporária, então adicione isso na junção - por exemplo, um inteiro calculado deCHECKSUM(customer_id, location_id, order_date)
ou algo semelhante.Ainda haveria um Filtro, mas o bitmap incluiria a coluna de soma de verificação, que poderia ser inserida na varredura. Isso deve reduzir significativamente o número de linhas passadas para o filtro.