A história de fundo:
Tenho uma tabela com a seguinte estrutura:
CREATE TABLE WideTable1
(
BoringColumn1,
BoringColumn2,
CellPhoneNumberColumn Phone(VARCHAR(20)), -- User-defined types, see below
PagerPhoneNumberColumn Phone(VARCHAR(20)), -- User-defined types, see below
IsActive YN(CHAR(1)), -- User-defined types, see below
BoringColumn3,
...
BoringColumn350
)
A consulta original que consumia essa tabela estava executando algumas funções SQL em CellPhoneNumberColumn e PagerPhoneNumber e, posteriormente, usando a saída dessas funções como predicados em outra consulta. NULLIF(LTRIM(ISNULL(CellPhoneNumberColumn, PagerPhoneNumberColumn)))
foi um exemplo disso.
As colunas também são todos os tipos definidos pelo usuário, neste caso CellPhoneNumberColumn e PagerPhoneNumberColumn são definidos como UDT Phone(VARCHAR(20))
, portanto, seu tipo de dados subjacente é VARCHAR(20)
. E IsActive é definido como YN(CHAR(1)) então é na verdade um CHAR(1).
Além disso, para complicar ainda mais as coisas, o agrupamento desta tabela/banco de dados é Latin1_General_BIN
.
Para encurtar a história, a consulta de consumo original estava enfrentando problemas de estimativa de cardinalidade. Na tentativa de aliviar o problema, criei uma visualização de índice nas colunas acima e funções SQL sendo aplicadas a elas com a seguinte definição (*observe que não criei essa lógica original, apenas tentando corrigir o desempenho dela):
CREATE VIEW PhoneNumbersNormalized WITH SCHEMABINDING AS
SELECT
NULLIF(LTRIM(ISNULL(CAST(CellPhoneNumberColumn AS VARCHAR(20)), CAST(PagerPhoneNumberColumn AS VARCHAR(20)))) AS Cell,
SUM(CASE WHEN CAST(IsActive AS CHAR(1)) = 'Y'THEN 1 ELSE 0 END) AS IsActive
FROM dbo.WideTable1
GROUP BY NULLIF(LTRIM(ISNULL(CAST(CellPhoneNumberColumn AS VARCHAR(20)), CAST(PagerPhoneNumberColumn AS VARCHAR(20))))
Também criei os seguintes índices na view indexada PhoneNumbersNormalized:
CREATE UNIQUE CLUSTERED INDEX IXV_PhoneNumbersNormalized_Cell ON dbo.PhoneNumbersNormalized(Cell)
CREATE NONCLUSTERED INDEX IXV_NC_PhoneNumbersNormalized_Cell_IsActive ON dbo.PhoneNumbersNormalized(Cell, IsActive)
O problema: quando seleciono na exibição indexada PhoneNumbersNormalized com o Plano de Execução Real incluído, notei que o plano de execução menciona especificamente a tabela subjacente original WideTable1 como de onde os dados estão vindo.
Além disso, se eu selecionar na exibição indexada PhoneNumbersNormalized com uma dica indexada no índice não clusterizado que criei acima IXV_NC_PhoneNumbersNormalized_PhoneNumber_IsActive
, o plano de execução não mostra nenhuma menção a esse índice não clusterizado sendo usado, em vez disso, ele diz que uma verificação de índice clusterizado é o que está fazendo (observe que ofusquei o original nome da tabela, na verdade não é chamado WideTable1 no meu servidor):
Plano de execução colado: https://www.brentozar.com/pastetheplan/?id=HJytxh2UP
Por que o plano de execução está sempre mostrando a tabela subjacente original em vez da exibição indexada e sempre usando o índice clusterizado na tabela subjacente, mesmo quando minha consulta de seleção na exibição indexada usa uma dica de índice para forçar o uso do índice não clusterizado ?
Sua definição de visualização está sendo expandida. Você precisará da dica NOEXPAND .
Dos documentos : O otimizador de consulta trata a exibição como uma tabela com índice clusterizado. NOEXPAND aplica-se apenas a exibições indexadas.
Ser vinculado ao esquema é uma propriedade de objeto que pode ser aplicada a outras coisas além de exibições, como funções. No entanto, você não pode indexar uma exibição que não esteja vinculada ao esquema.
Para um exemplo com funções, confira este Q&A: