Estou implantando uma tabela de mapeamento que se conecta Items
aItemGroups
Embora um Item
sempre esteja em um único ItemGroup
, aceite a priori que não é apropriado em meu caso de uso anexar uma coluna à Items
tabela.
Assim será criada uma tabela com duas colunas:
ItemId INT NOT NULL
ItemGroupId INT NOT NULL
É tentador fazer ItemId
o CI e PK para esta tabela.... mas isso é adequado? Acho que faz sentido como uma chave primária, mas como não é sequencial nem perpetuamente crescente, parece incorreto como um CI. Eu nunca executarei consultas de intervalo contraItemId
... Mas uma chave substituta apenas para fins de um IC sequencial também não parece apropriada.
Tenho a mesma probabilidade de executar:
SELECT [ItemGroupId] FROM [Table] WHERE [ItemId] = @id
SELECT [ItemId] FROM [Table] WHERE [ItemGroupId] = @id
Tanto quanto eu posso dizer, tenho poucas opções:
ItemId
é o CI e o PKItemId
não é o CI, mas é o PKItemId
não é o CI nem o PK, mas tem umaUNIQUE
restriçãoItemId, ItemGroupId
combinação torna-se o PK eItemId
tem umaUNIQUE
restrição
Opção 5:
(ItemGroupId, ItemId)
(observe a ordem) como a chave primária (agrupada)ItemId
Embora pesquisar por
ItemId
não conduza a varreduras de intervalo (ainda?), pesquisar porItemGroupId
é 1 , o que o torna um bom candidato para ser a coluna inicial da chave de índice clusterizado.Meu design normal para esse tipo de tabela é indexar ambas as combinações, ou seja,
(Column1, Column2)
e(Column2, Column1)
assim eu (e outros) nunca preciso pensar se ela está indexada corretamente; apenas isso. No seu caso aqui, uma combinação é degenerada e, portanto, apenas uma coluna vai para a chave, mas a coluna não-chave ainda é coberta pelo índice porque faz parte da chave do índice clusterizado. A situação se torna mais complicada, é claro, se houver colunas não-chave envolvidas, mas isso está além do escopo do que você perguntou aqui.Nesse caso, embora você possa inverter a chave primária com a restrição exclusiva, escolhi a chave primária de 2 colunas de propósito porque ela será mais estável durante a vida útil da tabela. Isso funciona a seu favor como DBA (uma palavra: replicação) e também para desenvolvedores (pode haver muitas atualizações de código se a definição da chave primária mudar).
1 Pode haver um problema com a terminologia aqui. Pesquisar por um único
ItemId
retornará 0 ou 1 linha; pesquisar por um únicoItemGroupId
(uma chave incompleta) retorna >= 0 linhas, e assim é uma busca + varredura (ela aparecerá como uma busca de índice no plano de execução). Obviamente, isso não é uma "varredura de alcance" em váriosItemGroupId
s. A ideia é agrupar fisicamente (e ordenar, neste caso) osItemId
s para cadaItemGroupId
. Espero que esteja claro.