sql >> Databasteknik >  >> RDS >> Database

Vilken effekt kan olika marköralternativ ha?

Jag har skrivit flera gånger om hur man använder markörer och hur det i de flesta fall är mer effektivt att skriva om sina markörer med hjälp av set-baserad logik.

Jag är dock realistisk.

Jag vet att det finns fall där markörer är "obligatoriska" – du måste anropa en annan lagrad procedur eller skicka ett e-postmeddelande för varje rad, du utför underhållsuppgifter mot varje databas, eller du kör en engångsuppgift som helt enkelt är inte värt att lägga tid på att konvertera till set-baserat.

Hur du (förmodligen) gör idag

Oavsett anledningen till att du fortfarande använder markörer, bör du åtminstone vara försiktig så att du inte använder de ganska dyra standardalternativen. De flesta börjar sina markörer så här:

DECLARE c CURSOR FOR 
  SELECT whatever FROM ...

Nu igen, för ad-hoc, enstaka uppgifter, är detta förmodligen bara bra. Men det finns...

Andra sätt att göra det

Jag ville köra några tester med standardinställningarna och jämföra dem med olika marköralternativ som LOKALT , STATISK , READ_ONLY och FAST_FORWARD . (Det finns massor av alternativ, men det här är de som används oftast eftersom de är tillämpliga på de vanligaste typerna av marköroperationer som människor använder.) Jag ville inte bara testa råhastigheten för några olika kombinationer, utan även påverkan på tempdb och minne, både efter en kall serviceomstart och med en varm cache.

Frågan jag bestämde mig för att mata till markören är en mycket enkel fråga mot sys.objects , i exempeldatabasen AdventureWorks2012. Detta returnerar 318 500 rader på mitt system (ett mycket ödmjukt 2-kärnigt 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;

Sedan slog jag in den här frågan i en markör med olika alternativ (inklusive standardinställningarna) och körde några tester, mätte totalt serverminne, sidor allokerade till tempdb (enligt sys.dm_db_task_space_usage och/eller sys.dm_db_session_space_usage ), och total varaktighet. Jag försökte också observera tempdb-påståenden med hjälp av skript från Glenn Berry och Robert Davis, men på mitt ynka system kunde jag inte upptäcka några som helst påståenden. Naturligtvis är jag också på SSD och absolut inget annat körs på systemet, så det här kan vara saker du vill lägga till i dina egna tester om tempdb är mer sannolikt att vara en flaskhals.

Så till slut såg frågorna ut ungefär så här, med diagnostiska frågor som peppade in vid lämpliga 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;

Resultat

    Längd

    Den absolut viktigaste och vanligaste åtgärden är "hur lång tid tog det?" Tja, det tog nästan fem gånger så lång tid att köra en markör med standardalternativen (eller med bara LOCAL specificerad), jämfört med att ange antingen STATIC eller FAST_FORWARD :

    Minne

    Jag ville också mäta det extra minne som SQL Server skulle begära när man uppfyller varje markörtyp. Så jag startade helt enkelt om före varje kall cache-test, och mätte prestandaräknaren Totalt serverminne (KB) före och efter varje test. Den bästa kombinationen här var LOCAL FAST_FORWARD :

    tempdb-användning

    Detta resultat överraskade för mig. Eftersom definitionen av en statisk markör innebär att den kopierar hela resultatet till tempdb, och det uttrycks faktiskt i sys.dm_exec_cursors som SNAPSHOT , jag förväntade mig att träffen på tempdb-sidor skulle vara högre med alla statiska varianter av markören. Så var inte fallet; återigen ser vi en ungefär 5X träff på tempdb-användning med standardmarkören och den med bara LOCAL specificerat:

Slutsats

I flera år har jag betonat att följande alternativ alltid bör anges för dina markörer:

LOCAL STATIC READ_ONLY FORWARD_ONLY

Från och med denna tidpunkt, tills jag har en chans att testa ytterligare permutationer eller hitta fall där det inte är det snabbaste alternativet, kommer jag att rekommendera följande:

LOCAL FAST_FORWARD

(Som ett undantag körde jag också tester som utelämnade LOCAL alternativ, och skillnaderna var försumbara.)

Som sagt, detta är inte nödvändigtvis sant för *alla* markörer. I det här fallet talar jag enbart om markörer där du bara läser data från markören, endast i riktning framåt, och du inte uppdaterar den underliggande data (varken med tangenten eller med WHERE CURRENT OF<) /kod> ). Det är tester för en annan dag.


  1. Välj från tabell genom att bara veta datum utan tid (ORACLE)

  2. Leveransalternativ när du skickar in samtidig förfrågan i R12.1.3

  3. Tips för att lagra PostgreSQL-säkerhetskopior på Google Cloud (GCP)

  4. Dynamic Sampling Killing Me i 12c