Benutzerdefinierte Berichte und Indizes

Was mich immer schon gestört hat, war die Schwierigkeit sich einen schnellen Überblick über die Indizes einer Tabelle zu verschaffen. Insbesondere wenn man auf "fremden" Datenbanken Optimierungen machen soll, kann es schon mal nervig sein sich durch eine Handvoll Indizes zu klicken, um die Entscheidungen des Optimizers zu verstehen. Mit einem benutzerdefinierten Bericht ist der erste Einstieg aber einfach.

Benutzerdefinierte Bericht

Diese Art im Management Studio eigene Berichte auszuführen, gibt es schon seit der Version SQL Server 2005. Seit kurzem sind auch die Parameter für diese Art der Berichte schön dokumentiert.

In dem Artikel Use Custom Reports with Object Explorer Node Properties werden die möglichen Parameter beschrieben, die man übergeben bekommen kann um anschließend selber seine Abfrage durch diese Werte zielgenau anzupassen.

Als Parameter haben wir also:

  • ObjectName
  • ObjectTypeName
  • Filtered
  • ServerName
  • FontName
  • DatabaseName

Die Felder sind alle vom Typ String, bis auf das Feld "Filtered", welches Boolean ist. Auf der oben genannten Seite gibt es auch den Code für einen Beispiel-Report, der alle Parameter verwendet und deren Inhalt anzeigt. Hier kann man schon mal einen Eindruck gewinnen, welche Daten zu erwarten sind.

Wer den Code aus dem oben genannten Link verwendet, sollte darauf achten das <pre> tag am Anfang und Ende des Textes wieder zu entfernen!

Eine Besonderheit haben die benutzerdefinierten Berichte noch: Die Datenquelle die man während der Erstellung definiert hat, wird zur Ausführungszeit auf die aktuelle Server-Verbindung abgeändert.
Hat man sich also einen Bericht erstellt, kopiert man am besten die rdl-Datei in einen Pfad, der für das Management Studio einfach erreichbar ist. Bei mir ist es "Eigene Dokumente\SQL Server Management Studio\Custom Reports". Ein Rechtsklick auf ein Objekt im Objekt-Explorer bietet unter "Berichte" die Möglichkeit die Standard-Berichte auszuführen und unter "Benutzerdefinierte Berichte" kann man sich andere selbst erstellte Berichte auswählen. Glücklicherweise merkt sich das Management Studio, welche Berichte man wo verwendet hat und so bekommt man in der Regel eine überschaubare Anzahl bereits verwendeter Berichte vorgeschlagen.

Indizes Überblick

Jetzt können wir also die erste Abfrage zu den Indizes erstellen. Hierzu deklariere ich mir im Management Studio eine Variable, deren Platz später im Report der Parameter einnehmen wird. So kann man schon mal vorab das SQL in einer gescheiten Umgebung entwickeln.

DECLARE @ObjectName SYSNAME = '[dbo].[InsideSQL]';

SELECT s.name AS SchemaName,
    
t.name AS TableName,
    
ind.name AS IndexName,
    
ind.type_desc,
    
ind.is_unique, ind.is_primary_key,
    
LEFT(MyIndexspalten, LEN(MyIndexspalten)-1) +
    
COALESCE(' - (Included: ' + LEFT(MyIncluded, LEN(MyIncluded)-1) +')' ,'') AS Indexspalten
FROM sys.tables t
INNER JOIN sys.indexes ind
  
ON ind.OBJECT_ID = t.OBJECT_ID      
INNER JOIN sys.schemas s
  
ON t.schema_id = s.schema_id
-- Indexspalten
CROSS APPLY
  
(SELECT CAST(col.name AS NVARCHAR(32)) +  CASE WHEN ic.is_descending_key = 1 THEN ' (Desc)' ELSE '' END + ', '
    
FROM sys.index_columns ic
  
INNER JOIN sys.columns col
      
ON ic.OBJECT_ID = col.OBJECT_ID AND ic.column_id = col.column_id
  
WHERE ind.OBJECT_ID = ic.OBJECT_ID
  
AND ind.index_id = ic.index_id
  
AND ic.is_included_column = 0
  
ORDER BY ic.key_ordinal
    
FOR XML PATH('')) AS x(MyIndexspalten)
-- Included-Spalten
CROSS APPLY
  
(SELECT CAST(col.name AS NVARCHAR(32)) +  CASE WHEN ic.is_descending_key = 1 THEN ' (Desc)' ELSE '' END + ', '
    
FROM sys.index_columns ic
  
INNER JOIN sys.columns col
      
ON ic.OBJECT_ID = col.OBJECT_ID AND ic.column_id = col.column_id
  
WHERE ind.OBJECT_ID = ic.OBJECT_ID
  
AND ind.index_id = ic.index_id
  
AND ic.is_included_column = 1
  
ORDER BY ic.key_ordinal
    
FOR XML PATH('')) AS y(MyIncluded)
WHERE
  
t.is_ms_shipped = 0
  
AND ind.type_desc <> 'HEAP'
  
AND QUOTENAME(s.name) + '.' + QUOTENAME(t.name) = @ObjectName
ORDER BY
    
t.name, Indexspalten  ;

Wir wollen also zu der Tabelle [dbo].[Merkmale] alle Indizes mit ihren Spalten sehen. Für dieses Beispiel ist das Ergebnis noch überschaubar:

SchemaNameTableNameIndexNametype_descis_uniqueis_primary_keyIndexspalten
dboInsideSQLXIE1InsideSQLNONCLUSTERED00Merkmal, Wert
dboInsideSQLXPKInsideSQL CLUSTERED 11MyPk, Merkmal
dboInsideSQLXIE2InsideSQLNONCLUSTERED00Wert, Merkmal
dboInsideSQLXAK1InsideSQLNONCLUSTERED10Wert, Merkmal, MyPk

Der Report

Was eben noch eine deklarierte Variable war, ist jetzt ein Parameter für den Report: ObjectName. Zusätzlich verwende ich noch ServerName und DatabaseName um die Aussage des Berichts etwas sprechender zu machen.

Diese Werte gebe ich einfach per Ausdruck im Report aus und anschließend eine Tabelle mit dem Ergebnis des (jetzt parametrisierten) SQL Statements.
Das Ergebnis sieht dann so aus, wenn man den Bericht aus dem Objekt Explorer von der Tabelle dbo.InsideSQL her aufruft:

  insidesql_indizes_ueberblick.rdl

Fazit

Eigentlich ganz einfach einen schnellen Überblick über die Indizes zu bekommen und mit den benutzerdefinierten Berichten haben wir noch ganz andere Möglichkeiten. Mehr dazu gab es schon in diesem blog und es werden bestimmt noch einige Artikel folgen!