2008-10-30 13 views
12

Offensichtlich (methinks), ist das Erstellen eines Index auf einer BIT Spalte unnötig. Wenn Sie jedoch eine Spalte haben, in der Sie suchen müssen, in der jeder Wert wahrscheinlich eindeutig ist, wie BlogPost oder StreetAddress oder so, dann erscheint ein Index (wieder, methinks).Wann muss ein neuer SQL Server-Index erstellt werden?

Aber was ist der Cutoff? Was ist, wenn Sie 10.000 Zeilen erwarten und Sie etwa 20 eindeutige Werte darunter haben? Soll ein Index erstellt werden?

Vielen Dank im Voraus.

Antwort

15

Die beste Antwort darauf ist, Ihre Abfragen zu profilieren und festzustellen, ob der Index Ihre Abfragen verbessert. Die Schwierigkeit bei der Beantwortung dieses Problems besteht darin, dass es nahezu unmöglich ist, das Verhalten des Abfrageoptimierers zu verallgemeinern.

Eine Faustregel besagt, dass Ihre Selektivität bei einer gegebenen Abfrage in einer Tabelle 10% oder weniger beträgt. Dann profitieren Sie höchstwahrscheinlich von einem Index. In Ihrem Beispiel können Sie also von einem Index profitieren, wenn Ihre Werte gleichmäßig verteilt sind. Wenn Sie jedoch davon ausgehen, dass Ihr Tisch klein ist, kann Ihre Leistungssteigerung vernachlässigbar sein.

Dies ist keine feste Regel, da es viele Faktoren gibt, die die Anzahl von 10% ändern können, einschließlich der Verwendung eines gruppierten oder anderen Indextypen, Größe der Zeilen, wenn einige Spalten nicht inline sind Struktur usw.

Denken Sie auch daran, dass beim Einfügen in eine Tabelle mit einem Index eine erhebliche Leistungseinbuße entsteht. Wenn diese Tabelle häufig aktualisiert oder angehängt wird, kann der Geschwindigkeitsschub aus dem Index durch die langsameren Einfügungen und Aktualisierungen negiert werden.

Siehe den MSDN-Artikel unter Tablescan vs Index access.

Bearbeiten: Wie andere bereits erwähnt haben, kann Ihre Abfrage von einem Index profitieren, wenn Sie Aggregationsabfragen durchführen, z. B. das Zählen der Häufigkeit, mit der ein bestimmter Wert angezeigt wird. Sie können auch davon profitieren, wenn Sie häufig nach einer bestimmten Spalte sortieren.

1

In der Spalte, die Sie vorschlagen, wäre es sinnvoll, eine Referenz- oder Nachschlagetabelle für die Daten zu erstellen, um Datenredundanz zu vermeiden. Dies würde Ihre Spalte zu einem Fremdschlüssel machen, der auf die PK der neuen Nachschlagetabelle hinweist.

Alle Fremdschlüsselspalten sollten indiziert werden.

Ansonsten würde ich vermeiden, einen Index unter normalen Bedingungen auf einer solchen Spalte zu platzieren.

1

Erstellen eines Index auf einer BIT Spalte ist nicht erforderlich.

Sie wären überrascht. obwohl

SELECT foo.Name FROM foo WHERE foo.Active = 1 

Es war etwa 300.000 Zeilen in der Tabelle: einen Index zu erstellen, die ein bisschen Spalte für eine Abfrage wie

ich habe.

+0

Welcher Anteil der Zeilen Active = 1 tat, um andere mögliche Werte im Vergleich dar? Ich vermute, es war eine relativ kleine Teilmenge der gesamten Tabelle. –

+1

Es funktioniert nicht. Ich habe es versucht und MS hat es bestätigt - niedrige Kardinalitätsindizes werden ignoriert, egal wie die Proportionen sind. – dkretz

2

James schlug den Nagel auf den Kopf. Ich füge nur hinzu, dass sogar eine Bit-Spalte von einem Index profitieren könnte, abhängig davon, wie Sie die Tabelle verwenden. Wenn Sie beispielsweise die Anzahl der Zeilen mit einer 1 mehrmals täglich zählen möchten, kann ein Index hilfreich sein.Bei Indizes geht es nicht immer darum, einen einzelnen Datensatz zu finden - sie können auch für Aggregationen verwendet werden.

+1

Es wird nicht funktionieren. Ich weiß aus schmerzlicher Erfahrung, dass SQL Server keinen Index mit Kardinalität 2 verwendet, auch wenn 1 Datensatz den Wert "1" hat und 10 Millionen Datensätze den Wert "0" haben. – dkretz

+0

@doofledorfer: Ich bin sicher, dass das stimmt. Hast du ein aktuelles Beispiel? –

0

Ich würde sagen, es hängt alles davon ab, wie die Tabelle verwendet wird und die Gesamtsystemanforderungen. Wenn es beispielsweise Teil eines großen JOIN-Objekts ist und das übergeordnete Element eine große Berichtstyp-Tabelle ist, dann sollte der Index sicher sein. Wenn es im Vergleich zu anderen Tabellen in der Datenbank relativ klein ist und stark eingefügt und selten gelesen wird, ist ein Index wahrscheinlich nicht erwünscht.

Aber der Umfang der Operation in der gesamten Datenbank im Vergleich zu verfügbaren Ressourcen zuzuordnen ist der entscheidende Entscheidungsfaktor. So verhält sich dieser Tabelle + mögliche Index im gesamten System im Vergleich zu allen anderen Tabellen und deren Anforderungen. Wenn Sie das große Bild nicht im Hinterkopf behalten, können Sie das ganze System töten, indem Sie versuchen, eine willkürliche Regel einfach anzuwenden, um eine willkürliche Regel anzuwenden.

2

Indizes mit geringer Kardinalität sind sehr problematisch. Wenn es nur mehrere mögliche Werte gibt, scannt SQL Server fast immer Index-Scans, unabhängig von den Proportionen.

Beispiel: Ich hatte eine Tabelle mit einem Statusfeld, das nur die Werte "A", "N" und "R" (für Aktiv, Neu und Zurückgezogen) akzeptiert hat. Normalerweise würden Sie sich einer Bedingung nähern wo 95% "R" waren, waren 4 +% "A" und einige waren "N". SELECT WHERE state = 'N' würde Table-Scan, egal was.

ABER - es gibt einen neuartigen Indextyp namens Filtered Index,, der schließlich diese Bedingung behandelt. Es ist auch praktisch, wenn Sie Datensätze mit NULL-Werten ausschließen möchten.

0

Sie sollten Ihre Indizes auch sorgfältig untersuchen, wenn Sie bei Abfragen Deadlocks feststellen, normalerweise zwischen einem SELECT und einem INSERT/UPDATE. Ein schlecht gewählter Index kann zu Deadlocks beitragen, da er überhaupt keinen Index haben kann. Weitere Informationen finden Sie unter this knowledge base Artikel. Normalerweise hilft das Hinzufügen eines Indexes oder das Ändern der darin enthaltenen Spalten bei der Behebung solcher Deadlocks. Stellen Sie sicher, dass Sie den Abfrageplan der betroffenen Abfragen überprüfen.

0

eine der beste Weg ist, den Einsatz, die Ansichten in SQL Server-MVP i sugest 1 Woche tun sie nicht starten Sie Ihren Server für und dann diese Abfrage ausführen:

USE master; 
Go 
SELECT d.database_id, 
    d.object_id, 
    d.index_handle, 
    d.equality_columns, 
    d.inequality_columns, 
    d.included_columns, 
    d.statement AS fully_qualified_object, 
    gs.* 
FROM sys.dm_db_missing_index_groups g 
JOIN sys.dm_db_missing_index_group_stats gs ON gs.group_handle = g.index_group_handle 
JOIN sys.dm_db_missing_index_details d ON g.index_handle = d.index_handle 

Go 

SELECT mig.index_group_handle, 
    mid.index_handle, 
    migs.avg_total_user_cost AS AvgTotalUserCostThatCouldbeReduced, 
    migs.avg_user_impact AS AvgPercentageBenefit, 
    'CREATE INDEX missing_index_' + CONVERT (varchar, mig.index_group_handle) 
    + '_' + CONVERT (varchar, mid.index_handle) 
    + ' ON ' + mid.statement 
    + ' (' + ISNULL (mid.equality_columns,'') 
    + CASE 
     WHEN mid.equality_columns IS NOT NULL AND mid.inequality_columns 
     IS NOT NULL THEN ',' 
     ELSE '' 
    END 
    + ISNULL (mid.inequality_columns, '') 
    + ')' 
    + ISNULL (' INCLUDE (' + mid.included_columns + ')', '') AS create_index_statement 
FROM sys.dm_db_missing_index_groups mig 
INNER JOIN sys.dm_db_missing_index_group_stats migs ON migs.group_handle = mig.index_group_handle 
INNER JOIN sys.dm_db_missing_index_details mid ON mig.index_handle = mid.index_handle 
Order By migs.avg_user_impact Desc 

dann Ihre Tabellen überprüfen und requerd Index erstellen.

0

Es gibt gute Antworten bereits hier gepostet ... Fügen Sie einfach meine zwei Cents .... Führen Sie den fehlenden Index DMV und sehen, ob die Tabelle, die Sie erwähnten, als Kandidat für die Erstellung neuer Index aufgeführt ist und siehe die Definition von Der Index.

Von Are you using SQL's Missing Index DMVs?

SELECT 
    migs.avg_total_user_cost * (migs.avg_user_impact/100.0) * (migs.user_seeks + migs.user_scans) AS improvement_measure, 
    'CREATE INDEX [missing_index_' + CONVERT (varchar, mig.index_group_handle) + '_' + CONVERT (varchar, mid.index_handle) 
    + '_' + LEFT (PARSENAME(mid.statement, 1), 32) + ']' 
    + ' ON ' + mid.statement 
    + ' (' + ISNULL (mid.equality_columns,'') 
    + CASE WHEN mid.equality_columns IS NOT NULL AND mid.inequality_columns IS NOT NULL THEN ',' ELSE '' END 
    + ISNULL (mid.inequality_columns, '') 
    + ')' 
    + ISNULL (' INCLUDE (' + mid.included_columns + ')', '') AS create_index_statement, 
    migs.*, mid.database_id, mid.[object_id] 
FROM sys.dm_db_missing_index_groups mig 
INNER JOIN sys.dm_db_missing_index_group_stats migs ON migs.group_handle = mig.index_group_handle 
INNER JOIN sys.dm_db_missing_index_details mid ON mig.index_handle = mid.index_handle 
WHERE migs.avg_total_user_cost * (migs.avg_user_impact/100.0) * (migs.user_seeks + migs.user_scans) > 10 
ORDER BY migs.avg_total_user_cost * migs.avg_user_impact * (migs.user_seeks + migs.user_scans) DESC 
Verwandte Themen