Parto da una considerazione che si trasforma in domanda:
Perchè SQL Server permette la creazione di un indice che è perfettamente identico (tipo, colonne indicizzate, colonne incluse) ad un indice già presente?
Mi aspetterei almeno un warning, invece nulla.
La seconda domanda:
Può avere senso avere due indici perfettamente identici? Forse in casi estremi di disponibilità di una delle due strutture mentre l’altra viene ricostruita?
Non so, francamente non vedo il senso nel 99% degli scenari e degli utilizzi.
Fatto sta che avere due (o più) indici identici non porta alcun beneficio, anzi.
Ho un overead inutile in fase di INSERT / UPDATE / DELETE, ho storage occupato inutilmente, le operazioni di backup / restore sono più lunghe, …
Detto questo, qual è il rischio in cui si può incorrere quando un progetto viene sviluppato da più persone, ovvero quando un database viene modellato da più mani?
Proprio questo: creare un indice che esiste già! :-(
E SQL Server non fa nulla per venirci in aiuto o, almeno, non fa nulla in automatico.
Quindi, armato di TSQL, viste di sistema, FOR XML (per mettere su una stessa riga informazioni diverse), … potrei verificare la presenza di indici identici in questo modo:
;WITH tIndex AS
(
SELECT
object_id AS id ,
index_id AS indid ,
type,
name ,
(
SELECT
colid as colPosition
FROM sys.sysindexkeys
WHERE id = I.object_id AND indid = I.index_id
AND keyno > 0
FOR XML PATH
) AS cols ,
(
SELECT includedCol FROM
(
SELECT
CASE keyno WHEN 0 THEN colid ELSE NULL END AS includedCol
FROM sys.sysindexkeys
WHERE id = I.object_id AND indid = I.index_id
) T0
order by includedCol
FOR XML PATH
) AS inc
FROM sys.indexes AS I
)
SELECT
object_schema_name ( T1.id ) + '.' + object_name ( T1.id ) as tableName,
T1.name AS indexName,
T2.name AS duplicateIndex,
S.used_page_count * 8 indexSizeKB
FROM tIndex AS T1
JOIN tIndex AS T2 ON
T1.type = T2.type AND
T1.id = T2.id AND
T1.indid < T2.indid AND
T1.cols = T2.cols AND
T1.inc = T2.inc
JOIN sys.dm_db_partition_stats AS S ON
S.[object_id] = T2.id AND S.index_id = T2.indId
ORDER BY object_schema_name ( T1.id ) + '.' + object_name ( T1.id ), T1.name
go
Provo a farne una verifica:
use tempdb
go
/* creo una tabella di esempio */
IF OBJECT_ID('dbo.anagrafica', 'U') IS NOT NULL
drop table dbo.anagrafica
go
create table anagrafica
(
idRecord smallint identity(1,1),
nome varchar(35),
cognome varchar(35),
cf char(16),
codice char(6)
)
go
/* credo tre indici, il primo cluster, gli altri due identici */
create clustered index idxAna1 on anagrafica (cf)
create nonclustered index idxAna2 on anagrafica (cf)
create nonclustered index idxAna3 on anagrafica (cf)
go
/* credo tre indici identici (anche con INCLUDE) */
create index idxAnaIncluded1 on anagrafica (cf) include (codice)
create index idxAnaIncluded2 on anagrafica (cf) include (codice)
create index idxAnaIncluded3 on anagrafica (cf) include (codice)
go
Questo il risultato:
Se lo provo sul database AdventureWorks (versione 2008)?
Che il db sia stato modellato da tante mani? :-)