Abfragen über mehrere Tabellen mit Indizes

20 replies [Letzter Beitrag]
WayneSchlegl
Offline
Joined: 16.02.2009

Hallo InsideSQLer,
Ich arbeite in einem Projekt mit das den MS SQL Server als Datenquelle nutzt.
Seit einiger Zeit befasse ich mit dem Thema Performance und daher natürlich Indizes.
Ich habe einiges über Indizes und die sinnvolle verwendung gelesen. Allerdings war da sehr wenig praktisches dabei.
Mich würde nun interessieren wie Ihre denn eure Indizes gesetzt habt.
Konkret: Ich habe eine Kundentabelle, die enthält unter anderem Nachname,Vorname,
das sind die Felder die vorrangig zur Suche genommen werden.
Die Tabelle Kunde hat einen Primärschlüssel, der gruppierte Index sitzt da auch drauf.
Eine Tabelle Adresse ist über den PS mit der Tabelle Kunde verknüpft.

Nun habe ich den Gruppierten Index auf die Spalten Nachname und Vorname verschoben,
dadurch hat sich am Ausführungsplan der Abfrage nix geändert.

Wie habt ihr eure Indizes gesetzt ?

admin
Offline
Joined: 19.12.2007

Aus dem Gefühl heraus würde ich sagen, dass der jetzige Clustered Index eher unglücklich gewählt ist und Du eher einen Nonclustered Index dafür einrichten solltest. Aber ohne die Abfrage und den Ausführungsplan zu sehen ist das alles eh wie ein Schuss im Dunkeln.
--
Frank Kalis
Microsoft SQL Server MVP
Webmaster: http://www.insidesql.org

WayneSchlegl
Offline
Joined: 16.02.2009

Hallo Frank,
Danke für die Infos. Ich werde den Plan und die Abfrage hier posten. Wie bist du an solche Problemstellungen heran gegangen ?
Ich habe viel mit dem Profiler gemacht, hier haben sich auch Erfolge eingestellt. Wie identifizierst du die langsamen Abfragen?

WayneSchlegl
Offline
Joined: 16.02.2009

doppelposting *g*

admin
Offline
Joined: 19.12.2007

Ueblicherweise mit dem Profiler und einem Filter auf Duration > n Millisekunden. Das gibt einen Eindruck von den absolut gesehen "teuersten" Abfragen. Allerdings kümmern mich Abfragen, die einmal pro Stunde oder so laufen und mal 5 Sekunden mehr oder weniger verbrauchen, eher nicht. Viel mehr Wert lege ich darauf, dass die Abfragen und Prozeduren, die - bei mir - bis zu 100.000 Mal pro Stunde ausgeführt werden, so effektiv wie möglich sind.

Ich analysiere aber auch bereits vorher, wie sich der Code verhält, ob Indizes genutzt werden und wie die Auswirkungen auf IO, usw... sind. Gerade bei Indizierung kommt man meiner Meinung nach kaum um umfangreiche Tests herum. Sowohl beim Index selber, als auch beim Code erreicht man manchmal durch eine kleine Umstellung eine ganze Menge.

Falls Du auf SQL Server 2005 oder besser entwickelst, solltest Du unbedingt mit der INCLUDE Klausel bei Indizes experimentieren. Die wird vielfach übersehen, bietet aber eine ausgezeichnete Möglichkeit eines "schlanken" Covering Index.
--
Frank Kalis
Microsoft SQL Server MVP
Webmaster: http://www.insidesql.org

Ebis
Offline
Joined: 20.12.2007

Beim 2008 werden dem SQL-Server fehlende Indices im Ausführungsplan angezeigt samt ihrem zu erwarteten Einfluss auf die Abfrage. Der Vorschlag vom SQL-Server kann dann über die rechte Maustaste in ein Abfrage-Fenster kopiert werden
Über --tasten-kombination kann dann ein passender Name vergeben werden.

beim 2005 kommt man da mit folgender Abfrage weiter:
(Quelle: K. Delaney et al. - Inside SQL-SERVER 2005 Query Tuning and Optimizing - Microsoft Press)

SELECT SDB.Name AS DBName
, SOB.Name AS TableName
, MID.Equality_Columns
, MID.InEquality_Columns
, MID.Included_Columns
, MID.Statement
, MIGS.Unique_Compiles
, MIGS.User_Seeks
, MIGS.User_Scans
, MIGS.Last_User_Seek
, MIGS.Last_User_scan
, MIGS.Avg_total_user_Cost
, MIGS.Avg_User_Impact
, MIGS.System_Seeks
, MIGS.System_Scans
, MIGS.Last_System_Seek
, MIGS.Last_System_Scan
, MIGS.Avg_Total_System_Cost
, MIGS.Avg_System_Impact
FROM Sys.DM_DB_Missing_Index_Group_Stats AS MIGS
JOIN SYS.DM_DB_Missing_Index_Groups AS MIG ON MIGS.Group_Handle = MIG.Index_Group_Handle
JOIN SYS.DM_DB_Missing_Index_Details AS MID ON MIG.Index_Handle = MID.Index_Handle
JOIN Sys.Databases AS SDB ON SDB.Database_ID = MID.Database_id
JOIN Sys.Objects AS SOB ON SOB.Object_ID = MID.Object_ID

Ebis

WayneSchlegl
Offline
Joined: 16.02.2009

@admin,
Ich erstelle eine Kundentabelle mit Inidzes wie sie im echten Programm vorkommen und poste das mal.
Heute habe ich etwas mit den Indizes variiert und im Profiler die Werte angekuckt.
Konkret:
Ich habe auf die Kundentabelle auf die Spalten Nachnamen,Vorname,kundeid den gruppierten Index gesetzt und
einen Select (Select nachname,vorname from kunde where nachname like'%%' and vorname like '%%') ausgeführt.

Die Tabelle habe ich kopiert und beim 2.mal den gruppierten Index auf dem Feld Kundeid gelassen.

Führt man nun die Abfrage auf beiden Tabellen aus, so sieht man im Profiler dass
die Abfrage mit dem gruppierten Index auf Nachname,Vorname länger dauert (Spalte Duration),
aber sie erzeugt weniger reads (Spalte Reads).
Das hat mich doch sehr überrascht.
Aus meiner Warte würde ich sagen die Optimierung hat sich gelohnt, die Anzahl der Reads sind zurückgegangen, allerdings dauert die Abfrage trotzdem länger. Kann es sein dass die geringe Anzahl an Reads auch weniger Locks bedeutet?
Wayne

Muthmann
Offline
Joined: 20.12.2007

Hallo Wayne,
laut meinem Verständnis wird in beiden Fällen die oben genannte Abfrage zu Full-Table-Scans führen. Günstiger wäre die Verwendung der Volltext-Suche für diese Fälle.

In beiden Fällen wird die Anzahl der gelesenen Zeilen gleich sein, insofern sollten auch die Sperren gleich bleiben.
Zur Vermeidung von Sperrsituationen gibt es ab SQLServer 2005 die Zeilenversionsverwaltung.
http://www.insidesql.org/beitraege/administration/zeilenversionsverwaltu...

Einen schönen Tag noch,
Christoph Muthmann
Microsoft SQL Server MVP

admin
Offline
Joined: 19.12.2007

Wenn du wirklich solche Abfragen absetzt wie

Select nachname,vorname from kunde where nachname like'%%' and vorname like '%%'

dann kannst Du die WHERE KLausel auch gleich ganz weglassen, da eh immer alle Daten zurückgegeben werden, was einem Scan gleichkommt. Da würde ich vielleicht wirklich über einen nonclustered index über diese beiden Spalten nachdenken und mir den clustered index für "bessere" Kandidaten aufsparen.
--
Frank Kalis
Microsoft SQL Server MVP
Webmaster: http://www.insidesql.org

WayneSchlegl
Offline
Joined: 16.02.2009

Das Beispiel sollte so aussehen: (Also mit Werten gefüllt)
Select nachname,vorname from kunde where nachname like'%weber%' and vorname like '%stefan%'

WayneSchlegl
Offline
Joined: 16.02.2009

Untersucht man die Ausführungspläne mit der option set showplan_xml on, sieht man dass der Index auf Nachname,Vorname nicht verwendet wird, wenn ein like Prädikator in der Abfrage enthalten ist.

admin
Offline
Joined: 19.12.2007

Das stimmt so nicht ganz.

Sähe Dein Prädikat wie LIKE 'Wayne%' so, kann SQL Server potentiell einen Index nutzen. Die Chancen dass bei einem Prädikat wie '%Wayne' ein Index genutzt werden kann, sind hingegen eher gering.

Und wenn die Abfrage zu viele Zeilen in Relation zur Gesamtzahl aller Zeilen der Tabelle zurückgibt, ist es oftmals einfacher, einen Index zu ignorieren und direkt die Tabelle zu scannen.
--
Frank Kalis
Microsoft SQL Server MVP
Webmaster: http://www.insidesql.org

WH
Offline
Joined: 20.12.2007

Hallo Leute,

bin gerade auch beim Optimieren der Abfragen, jedoch habe ich eine kleine Verständnisfrage. Ich arbeite mit dem SQL Server 2008 und bei einer Abfrage schlägt mir der Ausführungsplan einen Index auf einen Foreign-Key zu setzen. Jedoch habe ich auf dieser Seite (http://technet.microsoft.com/en-us/library/ms175464.aspx) gelesen, dass man bei einem FK keinen Index zu setzen braucht.

Wie ist es nun? Soll ich dem Ausführungsplan vertrauen?

Edit: Ich muss meine Frage zurückziehen. Hab die Seite falsch verstanden und außerdem steht es schon in einem anderen Post.

admin
Offline
Joined: 19.12.2007

Nur so am Rande...

Ich habe eine Tabelle mit z.Zt. 74 Mio. Zeilen, die monatlich netto um ca. 12 Mio. Zeilen wächst. Die Tabelle hat 3 Foreign-Key Spalten, die auf Lookup Tabellen verweisen. Momentan überlege ich ernsthaft die vorhandenen Indizes darauf zu löschen, da sie nicht verwendet werden und nur Platz verschwenden.
--
Frank Kalis
Microsoft SQL Server MVP
Webmaster: http://www.insidesql.org

Muthmann
Offline
Joined: 20.12.2007

Hi Frank,
ein Index über die FK-Spalte wird benötigt, wenn Du ein Delete auf die Lookup-Tabelle absetzt. Falls Du sowas nicht tust, dann kannst Du den Index ruhig löschen.

Einen schönen Tag noch,
Christoph Muthmann
Microsoft SQL Server MVP

tosc
Offline
Joined: 20.12.2007

Hi Frank, hi Christoph,
auch auf die Gefahr hin das ich falsch liege, beim "nicht verwendet ... und löschen" würde ich erst diese Tabelle mit dem Profiler überwachen - um sicher zu gehen ...

CU
tosc

Muthmann
Offline
Joined: 20.12.2007

Hi Torsten,
wenn man alle SQLs der Anwendung kennt, braucht man keinen Profiler. Ansonsten hast Du natürlich vollkommen Recht.

Einen schönen Tag noch,
Christoph Muthmann
Microsoft SQL Server MVP

tosc
Offline
Joined: 20.12.2007

:-) das hast Du aber nett geschrieben!

admin
Offline
Joined: 19.12.2007

Und da genau das der Fall ist, das von den Lookup Tabellen NIE gelöscht werden kann, spiele ich mit dem Gedanken, die Indizes zu löschen. :-)

... und Ja, ich kenne alle Statements die regulär per Prozedur abgesetzt werden können. Alles andere ich eh nicht möglich.
--
Frank Kalis
Microsoft SQL Server MVP
Webmaster: http://www.insidesql.org

tosc
Offline
Joined: 20.12.2007

:-) aufhören, es tut mir schon weh!

admin
Offline
Joined: 19.12.2007

[quote=tosc]:-) aufhören, es tut mir schon weh![/quote]
Nicht doch... ;-)
--
Frank Kalis
Microsoft SQL Server MVP
Webmaster: http://www.insidesql.org