Como fazer com que uma visão de união seja executada com mais eficiência?

8

Eu tenho uma tabela grande (dezenas a centenas de milhões de registros) que dividimos por motivos de desempenho em tabelas ativas e de arquivamento, usando um mapeamento de campo direto e executando um processo de arquivamento todas as noites.

Em vários lugares do nosso código, precisamos executar consultas que combinam as tabelas ativas e de arquivamento, quase invariavelmente filtradas por um ou mais campos (nos quais obviamente colocamos índices nas duas tabelas). Por conveniência, faria sentido ter uma visão como esta:

create view vMyTable_Combined as
select * from MyTable_Active
union all
select * from MyTable_Archive

Mas se eu executar uma consulta como

select * from vMyTable_Combined where IndexedField = @val

ele fará a união em tudo, desde Active e Store antes de filtrar @val, o que prejudicará o desempenho.

Existe alguma maneira inteligente de fazer com que as duas subconsultas da união visualizem cada filtro @valantes de criar a união?

Ou talvez exista alguma outra abordagem que você sugerir que atinja o que pretendo, ou seja, uma maneira fácil e eficiente de obter o conjunto de registros da união, filtrado pelo campo indexado?

EDIT: aqui está o plano de execução (e você pode ver os nomes das tabelas reais aqui):

plano de execução

Curiosamente, a tabela ativa está realmente usando o índice correto (mais uma pesquisa de RID?), Mas a tabela de arquivamento está fazendo uma varredura de tabela!

Shaul Behr
fonte
Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
Paul White 9

Respostas:

8

Os comentários sobre a pergunta mostram que o problema é que o banco de dados de teste que o OP estava usando para desenvolver a consulta tinha características de dados radicalmente diferentes do banco de dados de produção. Tinha muito menos linhas e o campo usado para filtragem não era seletivo o suficiente.

Quando o número de valores distintos em uma coluna é muito pequeno, o índice pode não ser suficientemente seletivo. Nesse caso, uma varredura seqüencial de tabela é mais barata que uma operação de busca de índice / linha. Normalmente, uma varredura de tabela faz uso extensivo de E / S seqüencial, o que é muito mais rápido do que as leituras de acesso aleatório.

Frequentemente, se uma consulta retornar mais do que apenas alguns por cento das linhas, será mais barato fazer uma varredura de tabela do que uma pesquisa de índice / pesquisa de linha ou operação semelhante que faça uso pesado de E / S aleatória.

ConcernedOfTunbridgeWells
fonte
1

Só para adicionar, o que eu encontrei. Se você fizer:

create view vMyTable_Combined as
select *, 1 AS [Active] from MyTable_Active
union all
select *, 0 AS [Active] from MyTable_Archive

Em seguida, você pode filtrar no campo [Ativo] e garantir que a outra parte não esteja carregada.

Michael Møldrup
fonte