sql >> Database teknologi >  >> RDS >> Database

Hvilken indflydelse kan forskellige markørmuligheder have?

Jeg har flere gange skrevet om at bruge markører, og hvordan det i de fleste tilfælde er mere effektivt at omskrive dine markører ved hjælp af sæt-baseret logik.

Jeg er dog realistisk.

Jeg ved, at der er tilfælde, hvor markører er "påkrævet" – du skal kalde en anden lagret procedure eller sende en e-mail for hver række, du udfører vedligeholdelsesopgaver mod hver database, eller du kører en enkeltstående opgave, der simpelthen er ikke værd at investere tid i at konvertere til sæt-baseret.

Hvordan du (sandsynligvis) gør det i dag

Uanset grunden til at du stadig bruger markører, skal du i det mindste passe på ikke at bruge de ret dyre standardindstillinger. De fleste mennesker starter deres markører sådan her:

DECLARE c CURSOR FOR 
  SELECT whatever FROM ...

Nu igen, for ad-hoc, enkeltstående opgaver, er dette nok helt fint. Men der er...

Andre måder at gøre det på

Jeg ønskede at køre nogle test ved hjælp af standardindstillingerne og sammenligne dem med forskellige markørindstillinger såsom LOCAL , STATISK , READ_ONLY og FAST_FORWARD . (Der er et væld af muligheder, men det er dem, der oftest bruges, da de er anvendelige til de mest almindelige typer markøroperationer, som folk bruger). også indvirkningen på tempdb og hukommelse, både efter en kold servicegenstart og med en varm cache.

Forespørgslen, jeg besluttede at sende til markøren, er en meget enkel forespørgsel mod sys.objects , i prøvedatabasen AdventureWorks2012. Dette returnerer 318.500 rækker på mit system (et meget ydmygt 2-core system med 4 GB RAM):

SELECT c1.[object_id] 
  FROM sys.objects AS c1
  CROSS JOIN (SELECT TOP 500 name FROM sys.objects) AS c2;

Så pakkede jeg denne forespørgsel ind i en markør med forskellige muligheder (inklusive standardindstillingerne) og kørte nogle tests, der målte Total Server Memory, sider allokeret til tempdb (ifølge sys.dm_db_task_space_usage og/eller sys.dm_db_session_space_usage ), og samlet varighed. Jeg forsøgte også at observere tempdb-stridigheder ved hjælp af scripts fra Glenn Berry og Robert Davis, men på mit sølle system kunne jeg ikke opdage nogen som helst påstand. Jeg er selvfølgelig også på SSD, og ​​absolut intet andet kører på systemet, så det kan være ting, du vil tilføje til dine egne tests, hvis tempdb er mere tilbøjelig til at være en flaskehals.

Så i sidste ende så forespørgslerne nogenlunde sådan her ud, med diagnostiske forespørgsler peppet ind på passende punkter:

DECLARE @i INT = 1;
 
DECLARE c CURSOR
-- LOCAL
-- LOCAL STATIC
-- LOCAL FAST_FORWARD
-- LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
  SELECT c1.[object_id] 
    FROM sys.objects AS c1
    CROSS JOIN (SELECT TOP 500 name FROM sys.objects) AS c2
    ORDER BY c1.[object_id];
 
OPEN c;
FETCH c INTO @i;
 
WHILE (@@FETCH_STATUS = 0)
BEGIN
  SET @i += 1; -- meaningless operation
  FETCH c INTO @i;
END
 
CLOSE c;
DEALLOCATE c;

Resultater

    Varighed

    Helt uden tvivl er den vigtigste og mest almindelige foranstaltning, "hvor lang tid tog det?" Nå, det tog næsten fem gange så lang tid at køre en markør med standardindstillingerne (eller med kun LOCAL specificeret), sammenlignet med at angive enten STATIC eller FAST_FORWARD :

    Hukommelse

    Jeg ønskede også at måle den ekstra hukommelse, som SQL Server ville anmode om, når hver markørtype blev opfyldt. Så jeg genstartede simpelthen før hver kold cache-test, og målte ydeevnetælleren Total Server Memory (KB) før og efter hver test. Den bedste kombination her var LOCAL FAST_FORWARD :

    tempdb-brug

    Dette resultat var overraskende for mig. Da definitionen af ​​en statisk markør betyder, at den kopierer hele resultatet til tempdb, og det er faktisk udtrykt i sys.dm_exec_cursors som SNAPSHOT , Jeg forventede, at hit på tempdb-sider ville være højere med alle statiske varianter af markøren. Dette var ikke tilfældet; igen ser vi et omkring 5X hit på tempdb-brug med standardmarkøren og den med kun LOCAL specificeret:

Konklusion

I årevis har jeg understreget, at følgende mulighed altid skal angives for dine markører:

LOCAL STATIC READ_ONLY FORWARD_ONLY

Fra dette tidspunkt, indtil jeg har mulighed for at teste yderligere permutationer eller finde tilfælde, hvor det ikke er den hurtigste mulighed, vil jeg anbefale følgende:

LOCAL FAST_FORWARD

(Som en side, kørte jeg også tests, hvor jeg udelod LOCAL mulighed, og forskellene var ubetydelige.)

Når det er sagt, er dette ikke nødvendigvis sandt for *alle* markører. I dette tilfælde taler jeg udelukkende om markører, hvor du kun læser data fra markøren, kun i en fremadgående retning, og du ikke opdaterer de underliggende data (enten med tasten eller ved hjælp af WHERE CURRENT OF ). Det er tests for en anden dag.


  1. GI 19c RPM Package Manager Database

  2. Introduktion til Native Dynamic SQL i Oracle-databasen

  3. Sådan opretter du en bruger med pgAdmin

  4. MySQL - ignorer indsættelsesfejl:dobbelt indtastning