Eu postei isso pela primeira vez no SO, mas não obtive respostas, esta é a razão pela qual estou tentando aqui agora e espero não estar quebrando nenhuma regra ao fazê-lo (dedos cruzados).
Estou tentando entender como usar o particionamento de tabelas e a eliminação de partições corretamente para poder decidir se quero usá-lo ou não em um novo banco de dados (sql server 17 express). Estou inclinado a não usá-lo, mas essa é uma história diferente, então essa pergunta é mais que eu não quero saber como funciona agora. No script a seguir eu crio uma função e esquema de particionamento, uma tabela usando o esquema, insiro alguns dados e depois consulto de 3 maneiras diferentes.
A primeira consulta está acessando corretamente apenas a primeira partição (contagem real de partições = 1, partições reais acessadas = 1).
Espero que a segunda consulta acesse apenas a primeira partição, já que criei a função de partição como intervalo no valor 20200101, mas ela está acessando as partições 1 e 2 (contagem real de partições = 2, partições reais acessadas = 1. .2).
Espero que a terceira consulta acesse apenas a partição 2, mas está acessando as partições 2 e 3 (contagem real de partições = 2, partições reais acessadas = 2..3).
Estou ciente de que preciso ter uma correspondência de tipo exata para que a eliminação de partição ocorra, mas acho que tenho isso aqui? o que estou perdendo?
create partition function partfun (datetime2(0))
as range right for values ('20200101', '20210101')
create partition scheme ps
as partition partfun all to ([primary])
create table t
(
id int not null identity(1,1),
logdate datetime2(0)
) on ps(logdate)
insert into t values ('20190101'),('20200102')
select * from t where logdate < cast('20191231' as datetime2(0))
select * from t where logdate < cast('20200101' as datetime2(0))
select * from t where logdate >= cast('20200101' as datetime2(0)) and t.logdate < cast('20210101' as datetime2(0))
Essas consultas triviais são parametrizadas automaticamente. Como tal, os valores literais são substituídos por parâmetros durante a compilação. As partições são eliminadas em tempo de execução dinamicamente usando a função interna RangePartitonNew em um predicado de busca de intervalo. É importante ressaltar que o intervalo inicial/final do predicado de busca é inclusivo para que o mesmo plano armazenado em cache possa ser reutilizado para qualquer valor possível, não apenas correspondências de limite exatas como em suas consultas. As linhas são posteriormente filtradas com base no
WHERE
predicado da cláusula para retornar apenas as linhas desejadas.Abaixo está o predicado de busca das primeiras 2 consultas. Em tempo de execução, a primeira consulta seek é equivalente a
partition_number >= 1 AND partition_number <= 1
e a segunda épartition_number >= 1 AND partition_number <= 2
. A partição 1 é codificada como o intervalo inicial devido ao operador menor que.O predicado de busca da terceira consulta difere apenas porque o intervalo inicial também inclui RangePartitionNew para eliminar partições excluídas pelo operador de comparação maior ou igual a. Esta busca é equivalente ao predicado
partition_number >= 2 AND partition_number <= 3
.Você pode evitar a parametrização simples com estas técnicas do artigo do blog de Paul :
WHERE 1 <> 2
Se os valores de limite exatos forem seu único caso de uso, você poderá adicionar um predicado para avaliar a função de partição com um operador de comparação menor que. Isso manterá os benefícios da parametrização. Por exemplo:
O predicado de busca de plano parametrizado resultante subtrai um do final do intervalo de limite para eliminar a partição excluída pelo predicado acima:
Observe que um índice na coluna de particionamento reduzirá a necessidade dessas soluções alternativas. Mesmo que uma partição extra seja tocada com valores de limite exatos, a sobrecarga é apenas algumas leituras lógicas adicionais.