32 messaggi dal 10 novembre 2005
Salve, ho un problema con degli indici su una tabella di SQL Server 2005.
Può essere che io stia facendo una domanda stupida ma purtroppo al momento non ne conosco la risposta

Ho una tabella Prodotti con qualche migliaio di record ed un indice nonclustered sulla colonna Categoria (di tipo varchar, chiave esterna alla tabella delle categorie)

Visualizzando il piano d'esecuzione di una semplice istruzione

SELECT * FROM Prodotto WHERE Categoria='xxx'

SQL Server utilizza un clustered index scan, non utilizzando l'indice che gli ho creato.

Sapete dirmi quale può essere il motivo?

Grazie
1.008 messaggi dal 19 dicembre 2003
Contributi | Blog
Il fatto che ci sia un indice non significa che SQL Server deve utilizzarlo a tutti i costi. L'indice verrebbe utilizzato solo ed esclusivamente se ritenuto utile. Come saprai recuperare un record tramite un indice non clustered significa accedere alla root dell'indice non clustered, navigarlo fino al livello foglia e qui recuperare la chiave clustered (se è presente un indice clustered, altrimenti il puntatore è rappresentato dal row id). Una volta recuperata la chiave clustered occorre accedere alla root dell'indice clustered e navigarlo fino al livello foglia dove sono i dati veri e propri. Se anzichè recuperare uno o pochi record devi recuperarne parecchi la cosa diventa via via sempre meno efficiente. Non a caso la selettività di un indice è uno dei fattori determinanti. Un indice che abbia una selettività pari all'1% è già un indice che avrà poche probabilità che venga utilizzato; il secondo fattore (di importanza pari al primo) è la dimensione della chiave di indice. Più è compatta la chiave e più sarà "piatta" (ovvero avrà meno livelli) la struttura di indice.
Immagina che ci siano, in una tabella 1 mln di record suddivisi in 10000 pagine (quindi circa 100 record a pagina). Se una query dovesse avere una condizione di ricerca che estragga circa 5000 record e questi record non sono, nelle pagine dati, adiacenti fra loro (altrimenti sarebbe un indice clustered), stai sicuro che la navigazione dell'indice non clustered per recuperare i 5000 (che da un punto di vista statistico, non avendo un indice clustered sul campo utilizzato dalla condizione di ricerca, ogni 2 pagine dati c'è uno dei record ceh vuoi recuperare) sarebbe molto superiore che non accedere alle 10000 pagine.
Non è una sorpresa, quindi, se un indice clustered non viene utilizzato per soddisfare una query anche se apparentemente (ovvero per il solo fatto di includere il campo nella condizione di ricerca) SQL Server dovrebbe utilizzarlo.
Fai anche riferimento a questo mio post

http://community.ugiss.org/blogs/lbianchi/archive/2007/04/26/misurare-l-utilit-di-un-indice.aspx

e se ti riesce recupera il thread a cui faccio riferimento

Bye

Luca Bianchi
Microsoft MVP - SQL Server
32 messaggi dal 10 novembre 2005
Perfetto, ti ringrazio. Avevo già letto vari articoli che parlano di indici ma questa tua risposta devo dire è stata la più chiara.
32 messaggi dal 10 novembre 2005
Mi sapresti anche suggerire un modo di rendere più efficiente la ricerca in questo caso?

Grazie di nuovo
1.008 messaggi dal 19 dicembre 2003
Contributi | Blog
nicholasp ha scritto:
Mi sapresti anche suggerire un modo di rendere più efficiente la ricerca in questo caso?


Solo (ma solo) se la chiave dell'indice è un varchar di pochi caratteri puoi pensare di rendere l'indice un indice di copertura per quella query. Un indice di copertura è un indice (di tipo non clustered) che al suo livello foglia ha TUTTI gli elementi per risolvere la query. Come ti ho detto nel precedente post, la livello foglia di un indice non clustered trovi il puntatore, rappresentato dalla chiave dell'indice clustered, per arrivare alla pagina dati. Se tutti i campi richiesti dalla query fossero presenti a questo livello non vi sarebbe alcuna ragione per accedere, tramite l'indice clustered, lla pagina dati. Immagina una query simile a

SELECT campo1, campo2, campo3
FROM dbo.MyTable
WHERE campo4 = 'xyz'

supponi che l'indice clustered sia su campo1 e l'indice non clustered sia campo4. Se aggiungi campo2 e campo3 alla definizione dell'indice su campo4 ecco li che tutti i campi utilizzati dalla query sono presenti al livello foglia dell'indice non clustered. Fino a SQL Server 2000 l'unico modo per fare ciò era rappresentato dal creare l'indice non clustered composto dai campi campo2+campo3+campo4 (secondo l'ordine che avresti ritenuto più appropriato). Questo però significava gravare l'indice con una chiave MOLTO più onerosa; in SQL Server 2005 è stata introdotta la possibilità di aggiungere dei campi SOLO al livello foglia di un indice non clustered (clausola INCLUDE). In questo modo potresti continuare ad avere l'indice non clustered sul campo4 ma puoi aggiungere (INCLUDE) campo2 e campo3 nella definizione dell'indice. In questo modo non vai a gravare sull'intera struttura ma solo sul livello foglia; il numero dei livelli b-tree rimane invariato ma il livello foglia sarà per forza di cose più vasto.
Nel tuo caso dove hai specificato il carattere [*] nella select list significa che dovresti includere tutti i campi della tabella (ad eccezione di quelli contenuti nella definizione dell'indice clustered) nella clausola include affinchè quello possa diventare un indice di copertura. Questo è uno solo dei tanti motivi per i quali è bene non utilizzare mai il carattere [*], ma se quelli che ti servono sono solo un sottoinsieme dei campi della tabella (e nel 99% dei casi è così) specificare nella select list i campi necessari contribuisce a creare query efficienti che potrebbero avvalersi (magari a tua insaputa) della presenza di un indice di copertura che, come ti sarai reso conto dalla mia spiegazione, rappresentano un benefit non indifferente quando utilizzabili. Ogni campo "superfluo" che chiedi che venga estratto ci mette del suo per limitare questa possibilità...

Bye

Luca Bianchi
Microsoft MVP - SQL Server
32 messaggi dal 10 novembre 2005
Perfetto veramente.
Nella mia query (che era un pò più complessa di come l'avevo scritta) non usavo [*] ma già una lista di campi, mi è bastato inserire l'indice come hai detto tu e le prestazioni sono subito aumentate.

Ti ringrazio veramente molto per l'aiuto e per le spiegazioni veramente chiare.

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.
Community
Ultimi messaggi
UTENTI ONLINE
In primo piano

I più letti di oggi

Media
In evidenza
MISC