sql >> Databasteknik >  >> RDS >> Database

Prestanda överraskningar och antaganden :STÄLL IN NOCOUNT PÅ

Om du någonsin har använt Management Studio kommer detta utdatameddelande förmodligen att se bekant ut:

(1 rad(er) påverkas)

Detta kommer från SQL Servers DONE_IN_PROC meddelande, som skickas vid framgångsrikt slutförande av en SQL-sats som har returnerat ett resultat (inklusive hämtning av en exekveringsplan, vilket är anledningen till att du ser två av dessa meddelanden när du faktiskt bara har kört en enda fråga).

Du kan undertrycka dessa meddelanden med följande kommando:

SET NOCOUNT ON;

Varför skulle du göra det? Eftersom dessa meddelanden är pratiga och ofta onyttig . I mina presentationer om dåliga vanor och bästa praxis pratar jag ofta om att lägga till SET NOCOUNT ON; till alla lagrade procedurer, och aktivera den i applikationskoden som skickar ad hoc-frågor. (Men under felsökningen kanske du vill ha en flagga för att aktivera meddelandena igen, eftersom utdata kan vara användbart i dessa fall.)

Jag har alltid lagt till friskrivningen att rådet att aktivera det här alternativet överallt inte är universellt; det beror på. Gamla ADO-postuppsättningar tolkade faktiskt dessa som resultatuppsättningar, så att lägga till dem i frågorna i efterhand kan faktiskt bryta applikationer som redan hoppar över dem manuellt. Och vissa ORM (hosta NHibernate hosta ) analyserar faktiskt resultaten för att avgöra framgången för DML-kommandon (ugh!). Testa dina ändringar.

Jag vet att jag vid ett tillfälle hade bevisat för mig själv att dessa chattiga meddelanden kunde påverka prestanda, särskilt över ett långsamt nätverk. Men det var länge sedan, och förra veckan frågade Erin Stellato mig om jag någonsin hade dokumenterat det formellt. Jag har inte, så här kommer. Vi tar en mycket enkel loop, där vi uppdaterar en tabellvariabel en miljon gånger:

SET NOCOUNT OFF;
 
DECLARE @i INT = 1;
DECLARE @x TABLE(a INT);
INSERT @x(a) VALUES(1);
 
SELECT SYSDATETIME();
 
WHILE @i < 1000000
BEGIN
  UPDATE @x SET a = 1;
  SET @i += 1;
END
 
SELECT SYSDATETIME();

Ett par saker du kanske lägger märke till:

  • Meddelanderutan är översvämmad med instanser av (1 row(s) affected) meddelande:

  • Initial SELECT SYSDATETIME(); visas inte i resultatrutan förrän efter att hela batchen har slutförts. Detta på grund av översvämningarna.
  • Denna batch tog cirka 21 sekunder att köra.

Låt oss nu upprepa detta utan DONE_IN_PROC meddelanden, genom att ändra SET NOCOUNT OFF; till SET NOCOUNT ON; och kör det igen.

Medan meddelanderutan inte längre var översvämmad med rad(er) påverkade meddelanden tog det fortfarande ~21 sekunder att köra batchen.

Sedan tänkte jag, vänta lite, jag vet vad som händer. Jag är på en lokal dator, utan nätverk inblandat, använder delat minne, jag har bara SSD och mängder av RAM...

Så jag upprepade testerna med min lokala kopia av SSMS mot en fjärrbaserad Azure SQL-databas – en Standard, S0, V12. Den här gången tog frågorna mycket längre tid, även efter att ha minskat iterationerna från 1 000 000 till 100 000. Men återigen fanns det ingen påtaglig skillnad i prestandan om DONE_IN_PROC meddelanden skickades eller inte. Båda satserna tog cirka 104 sekunder, och detta var repeterbart över många iterationer.

Slutsats

I flera år hade jag verkat under intrycket att SET NOCOUNT ON; var en kritisk del av varje prestationsstrategi. Detta baserades på observationer som jag hade gjort i, utan tvekan, en annan era, och som är mindre sannolikt att manifesteras idag.

Som sagt, jag kommer att fortsätta använda SET NOCOUNT ON , även om det på dagens hårdvara inte finns någon märkbar skillnad i prestanda. Jag känner fortfarande ganska starkt för att minimera nätverkstrafiken där det är möjligt. Jag borde överväga att implementera ett test där jag har mycket mer begränsad bandbredd (kanske någon har en AOL-cd de kan låna mig?), eller ha en maskin där minnesmängden är lägre än Management Studios utdatabuffertgränser, för att vara säker på att det finns är inte en potentiell påverkan i värsta fall. Under tiden, även om det kanske inte ändrar den upplevda prestandan för din applikation, kan det ändå hjälpa din plånbok att alltid aktivera det här inställningsalternativet, särskilt i situationer som Azure – där du kan debiteras för utgående trafik.


  1. Uppdatering av databasrader utan att låsa tabellen i PostgreSQL 9.2

  2. Hur ställer jag in tidszonen för MySQL?

  3. ORA-04091:tabellen [blah] muterar, trigger/funktion kanske inte ser den

  4. Anslutning kan inte castas till oracle.jdbc.OracleConnection