sql >> Database >  >> RDS >> Database

Kunnen opmerkingen de prestaties van opgeslagen procedures belemmeren?

Af en toe duikt er een gesprek op waarin mensen ervan overtuigd zijn dat opmerkingen wel of geen invloed hebben op de prestaties.

In het algemeen zal ik zeggen dat, nee, opmerkingen geen invloed hebben op de prestaties , maar er is altijd ruimte voor een "het hangt ervan af"-disclaimer. Laten we een voorbeelddatabase en een tabel vol rommel maken:

CREATE DATABASE CommentTesting;
GO
USE CommentTesting;
GO
SELECT TOP (1000) n = NEWID(), * INTO dbo.SampleTable 
  FROM sys.all_columns ORDER BY NEWID();
GO
CREATE UNIQUE CLUSTERED INDEX x ON dbo.SampleTable(n);
GO

Nu wil ik vier opgeslagen procedures maken - één met 20 tekens aan opmerkingen, één met 2000, één met 20.000 en één met 200.000. En ik wil dat opnieuw doen waar de opmerkingen zijn ingesloten *in* een query-instructie binnen de procedure, in plaats van onafhankelijk te zijn (wat een effect zal hebben op de plan-XML). Ten slotte herhaalde ik het proces door OPTION (RECOMPILE) toe te voegen op de vraag.

DECLARE @comments nvarchar(max) = N'', 
        @basesql  nvarchar(max),
        @sql      nvarchar(max);
 
SELECT TOP (5000) -- * 40 character strings
  @comments += N'--' + RTRIM(NEWID()) + CHAR(13) + CHAR(10)
FROM sys.all_columns;
 
SET @basesql = N'CREATE PROCEDURE dbo.$name$
AS
BEGIN
  SET NOCOUNT ON;
 
  /* $comments1$ */
 
  DECLARE @x int;
  SELECT @x = COUNT(*) /* $comments2$ */ FROM dbo.SampleTable OPTION (RECOMPILE);
END';
 
SET @sql = REPLACE(REPLACE(@basesql, N'$name$', N'Small_Separate'),      N'$comments1$', LEFT(@comments, 20));
EXEC sys.sp_executesql @sql;
 
SET @sql = REPLACE(REPLACE(@basesql, N'$name$', N'Medium_Separate'),     N'$comments1$', LEFT(@comments, 2000));
EXEC sys.sp_executesql @sql;
 
SET @sql = REPLACE(REPLACE(@basesql, N'$name$', N'Large_Separate'),      N'$comments1$', LEFT(@comments, 20000));
EXEC sys.sp_executesql @sql;
 
SET @sql = REPLACE(REPLACE(@basesql, N'$name$', N'ExtraLarge_Separate'), N'$comments1$', LEFT(@comments, 200000));
EXEC sys.sp_executesql @sql;
 
SET @sql = REPLACE(REPLACE(@basesql, N'$name$', N'Small_Embedded'),      N'$comments2$', LEFT(@comments, 20));
EXEC sys.sp_executesql @sql;
 
SET @sql = REPLACE(REPLACE(@basesql, N'$name$', N'Medium_Embedded'),     N'$comments2$', LEFT(@comments, 2000));
EXEC sys.sp_executesql @sql;
 
SET @sql = REPLACE(REPLACE(@basesql, N'$name$', N'Large_Embedded'),      N'$comments2$', LEFT(@comments, 20000));
EXEC sys.sp_executesql @sql;
 
SET @sql = REPLACE(REPLACE(@basesql, N'$name$', N'ExtraLarge_Embedded'), N'$comments2$', LEFT(@comments, 200000));
EXEC sys.sp_executesql @sql;

Nu moest ik de code genereren om elke procedure 100.000 keer uit te voeren, de duur meten van sys.dm_exec_procedure_stats , en controleer ook de grootte van het plan in de cache.

DECLARE @hammer nvarchar(max) = N'';
 
SELECT @hammer += N'
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;
GO
EXEC dbo.' + [name] + N';
GO 100000
 
SELECT [size of ' + [name] + ' (b)] = DATALENGTH(definition)
  FROM sys.sql_modules
  WHERE [object_id] = ' + CONVERT(varchar(32),([object_id])) + N';
 
SELECT [size of ' + [name] + ' (b)] = size_in_bytes
  FROM sys.dm_exec_cached_plans AS p
  CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t
  WHERE t.objectid = ' + CONVERT(varchar(32),([object_id])) + N';
 
SELECT N''' + [name] + N''', 
  avg_dur = total_elapsed_time*1.0/execution_count
  FROM sys.dm_exec_procedure_stats
  WHERE [object_id] = ' + CONVERT(varchar(32),([object_id])) + N';'
FROM sys.procedures
WHERE [name] LIKE N'%[_]Separate' OR [name] LIKE N'%[_]Embedded';
 
PRINT @hammer;

Laten we eerst eens kijken naar de grootte van de procedure-instanties. Geen verrassingen hier, ik bevestig alleen dat mijn constructiecode hierboven de verwachte grootte van opmerkingen in elke procedure genereerde:

Procedure Grootte (bytes)
Small_Separate / Small_Embedded 378
Medium_Separate / Medium_Embedded 4.340
Large_Separate / Large_Separate 40.338
ExtraLarge_Separate / ExtraLarge_Separate 400.348


Vervolgens, hoe groot waren de plannen in de cache?

Procedure Grootte (bytes)
Small_Separate / Small_Embedded 40.360
Medium_Separate / Medium_Embedded 40.360
Large_Separate / Large_Separate 40.360
ExtraLarge_Separate / ExtraLarge_Separate 40.360


Ten slotte, hoe was het optreden? Zonder OPTION (RECOMPILE) , hier is de gemiddelde uitvoeringstijd, in milliseconden - redelijk consistent voor alle procedures:


Gemiddelde duur (milliseconden) – zonder OPTIE (HERCOMPIEREN)

Met OPTION (RECOMPILE) . op instructieniveau , we kunnen over de hele linie een gemiddelde duur van ongeveer 50% zien vergeleken met geen hercompilatie, maar nog steeds redelijk gelijk:


Gemiddelde duur (milliseconden) – met OPTIE (HERCOMPIEREN)

In beide gevallen, terwijl de OPTION (RECOMPILE) versie liep over het algemeen langzamer, er was vrijwel NUL verschil in runtime, ongeacht de grootte van de opmerkingen in de hoofdtekst van de procedure.

Hoe zit het met hogere compilatiekosten?

Vervolgens wilde ik zien of deze grote opmerkingen een enorme impact zouden hebben op de compileerkosten, bijvoorbeeld als de procedures WITH RECOMPILE zouden zijn gemaakt . De constructiecode hierboven was eenvoudig te wijzigen om hiermee rekening te houden. Maar in dit geval kon ik niet vertrouwen op sys.dm_exec_procedure_stats , omdat dit niet werkt voor procedures WITH RECOMPILE . Dus mijn generatiecode voor de test was een beetje anders, omdat ik de gemiddelde duur handmatig zou moeten bijhouden:

DECLARE @hammer nvarchar(max) = N'';
 
SELECT @hammer += N'
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;
SELECT SYSDATETIME();
GO
EXEC dbo.' + [name] + N';
GO 100000
SELECT SYSDATETIME();';
 
PRINT @hammer;

In dit geval kon ik de grootte van de plannen in de cache niet controleren, maar ik kon de gemiddelde looptijd van de procedures bepalen, en er was een verschil op basis van de grootte van de opmerkingen (of misschien alleen de lichaamsgrootte van de procedure):


Gemiddelde duur (milliseconden) – MET RECOMPILE op procedureniveau

Als we ze allemaal samen in een grafiek zetten, is het duidelijk hoeveel duurder de WITH RECOMPILE gebruik kan zijn:


Gemiddelde duur (milliseconden) – alle drie de methoden vergelijken

Ik zal dit waarschijnlijk op een later tijdstip nader bekijken om te zien waar die hockeystick precies in het spel komt - ik zie testen in stappen van 10.000 tekens. Maar voor nu ben ik redelijk tevreden dat ik de vraag heb beantwoord.

Samenvatting

Opmerkingen lijken helemaal niets te maken te hebben met de werkelijke, waarneembare prestaties van de opgeslagen procedure, behalve in het geval dat de procedure is gedefinieerd WITH RECOMPILE . Persoonlijk zie ik dit niet meer in het wild worden gebruikt, maar YMMV. Voor de subtiele verschillen tussen deze optie en OPTION (RECOMPILE) , zie het artikel van Paul White, "Parameter Sniffing, Embedding, and the RECOMPILE Options."

Persoonlijk denk ik dat opmerkingen zeer waardevol kunnen zijn voor iedereen die uw code moet beoordelen, onderhouden of problemen moet oplossen. Dit omvat toekomstige jij. Ik raad ten zeerste af om je zorgen te maken over de prestatie-impact van een redelijk aantal opmerkingen, en in plaats daarvan te focussen op het prioriteren van het nut van de context die de opmerkingen bieden. Zoals iemand op Twitter al zei, er is een limiet. Als uw opmerkingen neerkomen op de verkorte versie van Oorlog en vrede, kunt u overwegen - met het risico de code los te koppelen van de documentatie - die documentatie ergens anders te plaatsen en naar de link in de opmerkingen van de proceduretekst te verwijzen.

Om het risico op ontkoppeling te minimaliseren, of dat de documentatie en code in de loop van de tijd niet meer synchroon lopen, kunt u een tweede procedure maken, met het achtervoegsel _documentation of _comments , en de opmerkingen (of een becommentarieerde versie van de code) daar te plaatsen. Zet het misschien in een ander schema om het uit de hoofdsorteerlijsten te houden. De documentatie blijft in ieder geval bij de database waar deze ook naartoe gaat, hoewel het niet garandeert dat het zal worden onderhouden. Het is jammer dat er geen normale procedure kan worden gemaakt WITH SCHEMABINDING , in dat geval zou je de commentaarprocedure expliciet aan de bron kunnen koppelen.


  1. Hoe de volledige MySQL-database te verwijderen

  2. Fatale fout:aanroep van een lidfunctie bind_param() op boolean

  3. Tabelstructuur herstellen van fr- en ibd-bestanden

  4. Oracle.DataAccess.Client.OracleException ORA-03135:verbinding verbroken contact