Datensatzlänge einer Abfrage schätzen
Gerade wenn man ein bestehendes Datenbanksystem optimieren möchte, könnte die Frage nach der durchschnittlichen Breite einer Abfrage auftauchen. Speziell wenn man keine Tabelle zur Hand hat die in ihren Properties zumindest den verbrauchten Speicherplatz anzeigt, ist die nachfolgende Prozedur vielleicht ganz nützlich.
Es werden für eine gegebene Abfrage die Ergebnisse in eine temporäre Tabelle geschrieben und dann mittels der Funktion DATALENGTH die tatsächliche Länge eines Feldes bestimmt. Die durchschnittliche Summe der Gesamtlänge eines Datensatzes wird in der Rückgabe angezeigt.
Wenn man diese Durchschnittslänge mit der Anzahl der Datensätze multipliziert, erhält man den Nettowert des Datenvolumens das transferiert wird. (zumindest annähernd;))
Wenn ein Feld einen NULL-Wert enthält, setzt die Prozedur eine Feldlänge von 4 Byte ein. Dies wird als Mittelwert einer leeren Feldlänge verwendet und könnte in einer weiteren Ausbaustufe ggf. noch aus den System-Views für die Feldtypen genauer bestimmt werden.
Die Abfrage sollte eine repräsentative Menge an Daten zurückliefern. Es ist vor allem bei sehr großen Ergebnismengen ein wenig Vorsicht angesagt, um nicht die Temp-Datenbank in Bedrängnis geraten zu lassen
| T-SQL | | copy code | | ? |
| 01 | CREATE PROCEDURE dbo.GetAvgRecordWidth |
| 02 | @Datenbank sysname |
| 03 | , @SourceCmd NVARCHAR(MAX) |
| 04 | AS |
| 05 | BEGIN |
| 06 | DECLARE @TempName NVARCHAR(1000) |
| 07 | DECLARE @IntoTemp NVARCHAR(1000) |
| 08 | |
| 09 | SET @TempName = '##TempCntSource_' + REPLACE(newid(),'-','') |
| 10 | |
| 11 | SET @IntoTemp = ' into ' + @TempName + ' FROM ' |
| 12 | |
| 13 | SET @SourceCmd = STUFF(@SourceCmd,CHARINDEX('from',LOWER(@SourceCmd)),4,@IntoTemp) |
| 14 | |
| 15 | -- --------------------------------------------------------------------------- |
| 16 | DECLARE @Cmd NVARCHAR(MAX) |
| 17 | |
| 18 | SET @Cmd = 'USE ' + @Datenbank + '; ' + @SourceCmd + N' |
| 19 | declare @SQL nvarchar(max) |
| 20 | ,@Feld sysname |
| 21 | ,@Delim varchar(100) |
| 22 | |
| 23 | set @Delim = N''Select avg('' |
| 24 | |
| 25 | set @SQL = N'''' |
| 26 | |
| 27 | declare Colcur cursor for |
| 28 | select c.name |
| 29 | from tempdb.sys.objects o |
| 30 | join tempdb.sys.columns c on c.object_id = o.object_id |
| 31 | where o.name like ''<##TempCntSource>%'' |
| 32 | |
| 33 | open Colcur |
| 34 | |
| 35 | fetch next from Colcur into @Feld |
| 36 | |
| 37 | while @@fetch_status = 0 |
| 38 | begin |
| 39 | set @SQL = @SQL + @Delim + ''isnull(DATALENGTH('' + @Feld + ''),4)'' |
| 40 | set @Delim = ''+'' |
| 41 | |
| 42 | fetch next from Colcur into @Feld |
| 43 | end |
| 44 | |
| 45 | close Colcur |
| 46 | deallocate Colcur |
| 47 | |
| 48 | set @SQL = @SQL + '') from <##TempCntSource>'' |
| 49 | |
| 50 | exec sp_executesql @SQL |
| 51 | |
| 52 | drop table <##TempCntSource> |
| 53 | ' |
| 54 | |
| 55 | SET @Cmd = REPLACE(@Cmd,'<##TempCntSource>',@TempName) |
| 56 | |
| 57 | EXEC SP_EXECUTESQL @Cmd |
| 58 | END |
Der Aufruf sieht dann wie folgt aus:
| T-SQL | | copy code | | ? |
| 1 | DECLARE @Stmt NVARCHAR(MAX) |
| 2 | DECLARE @Datenbank sysname |
| 3 | |
| 4 | SET @Datenbank = N'AdventureWorks' |
| 5 | SET @Stmt = N'select * from HumanResources.Employee' |
| 6 | |
| 7 | EXEC dbo.GetAvgRecordWidth @Datenbank,@Stmt |
have fun
Facebook
XING
META-SQL