Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Den här artikeln handlar om hur man skriver snabb PHP-kod mot SQL Server, Azure SQL Database, Azure SQL Managed Instance, Azure Synapse Analytics och SQL Database i Microsoft Fabric. Vägledningen gäller både SQLSRV och PDO_SQLSRV, som omsluter samma underliggande Microsoft ODBC-drivrutin för SQL Server.
Börja med de förändringar med störst påverkan
Om du bara kan göra tre ändringar, gör dessa:
- Aktivera anslutningspoolning. Att etablera en ny TLS-anslutning till SQL Server tar tiotals till hundratals millisekunder beroende på nätverksväg och TLS-förhandling. Att återanvända poolade anslutningar eliminerar den kostnaden per förfrågan. Se Hantera kontakter effektivt.
- Hämta bara de kolumner och rader du behöver.
SELECT *och obegränsade frågor är de vanligaste orsakerna till långsamma slutpunkter. Se Fråga bara efter det du behöver. - Använd tabellvärderade parametrar för bulkinsatser. För hundratals rader eller fler är tabellvärda parametrar (TVP) vanligtvis mycket snabbare än rad-för-rad-satser
INSERToch skalar linjärt med radantalet. Se Infoga data effektivt.
Hantera anslutningar effektivt
Anslutningsetablering är den enskilt dyraste operationen som föraren utför. Nästan varje PHP-prestandaundersökning slutar med en lösning för anslutningshantering.
Aktivera anslutningspooler
Pooling återanvänder ODBC-anslutningar mellan PHP-begäranden i stället för att stänga dem när begäran avslutas. Anslutningsobjektet frigörs när skriptet avslutas, men det underliggande ODBC-handtaget finns kvar i ODBC-drivrutinshanterarens pool och återanvänds av nästa begäran som använder samma anslutningssträng.
Windows: Anslutningspooling är påslagen som standard. För att bekräfta, lämna alternativet ConnectionPooling utanför ditt DSN. För att inaktivera pooling för felsökning, sätt ConnectionPooling=0.
Linux och macOS: Anslutningspooling är inte ett DSN-alternativ på dessa plattformar. Aktivera det i drivrutinshanteraren genom att ange Pooling=Yes i avsnittet [ODBC] i odbcinst.ini, och ange ett positivt CPTimeout-värde under drivrutinens sektion. Ett exempel:
[ODBC]
Pooling=Yes
[ODBC Driver 18 for SQL Server]
Description=Microsoft ODBC Driver 18 for SQL Server
Driver=/opt/microsoft/msodbcsql18/lib64/libmsodbcsql-18.<version>.so.1.1
CPTimeout=120
Hitta den faktiska biblioteksvägen med odbcinst -q -d -n "ODBC Driver 18 for SQL Server" eller ls /opt/microsoft/msodbcsql18/lib64/. Filnamnet bäddar in den installerade ODBC-drivrutinsversionen och ändras med varje release.
CPTimeout (i sekunder) styr hur länge inaktiva anslutningar förblir i poolen innan de stängs. Ställ in den tillräckligt högt för att de flesta förfrågningar ska hitta en poolad anslutning, men tillräckligt lågt för att gamla anslutningar till en failover-server tas bort ganska snabbt. 60 till 300 sekunder fungerar bra för de flesta webbarbetsbelastningar.
För detaljer, se Anslutningspooling.
Förstå kostnaden för första sökningen
Flera aktiva resultatuppsättningar (MARS) är aktiverat som standard. När både MARS och anslutningspooling är aktiva, återställer drivrutinen den poolade anslutningen på den första frågan, och den återställningen ignorerar eventuell frågetidsavslutning du ställt in för den första frågan. Senare förfrågningar på samma anslutning respekterar tidsgränsen som vanligt. Om du anger aggressiva tidsgränser för den första frågan för en poolad arbetsbelastning, ta hänsyn till det här beteendet, eller inaktivera MARS med MultipleActiveResultSets=false om du inte behöver det. Se kommentaren om MARS och poolning i Connection pooling.
Persistenta PDO-anslutningar stöds inte
PDO_SQLSRV avvisar PDO::ATTR_PERSISTENT. Att ange den på konstruktorn genererar ett undantag:
SQLSTATE[IMSSP]: An unsupported attribute was designated on the PDO object.
Använd ODBC connection pooling för återanvändning av korsförfrågningar. Det är den drivrutinsinbyggda mekanismen, den fungerar för både PDO_SQLSRV och SQLSRV och avvecklar inaktiva anslutningar vid CPTimeout (vilket också ser till att uppdateringen av Microsoft Entra-tokenen fungerar korrekt).
Återanvänd anslutningen inom en begäran
Även med pooling innebär öppnandet av en ny PDO- eller SQLSRV-anslutning en ODBC-rundresa för att hämta och validera ett poolat handtag. Öppna en anslutning en gång per förfrågan och skicka den till varje funktion som behöver den.
Tips/Råd
En beroendeinjektionsbehållare eller en lat accessor räcker. Poängen är att undvika new PDO(...) mitt i en hanterare för begäranden.
Fråga bara efter det du behöver
Nätverksrundresor och materialisering av resultatuppsättningar dominerar frågefördröjning för de flesta PHP-arbetsbelastningar. Fixarna är samma som gäller för varje databasåtkomstlager.
Välj endast de kolumner du använder
SELECT * hämtar alla kolumner, inklusive varchar(max)- och varbinary(max)-kolumner som är mycket större än de data du faktiskt använder. Namnge kolumnerna:
<?php
// Slow: fetches all columns, including a 2 MB LOB column
$stmt = $conn->query("SELECT * FROM dbo.Products");
// Fast: fetches only the two columns the caller uses
$stmt = $conn->query("SELECT ProductID, Name FROM dbo.Products");
Hämta bara de rader du behöver
Skicka filtreringen till SQL Server. Hämta aldrig en hel tabell i PHP bara för att filtrera i en foreach loop.
<?php
// Slow: transfers every row to PHP, then filters
$rows = $conn->query("SELECT * FROM dbo.Orders")->fetchAll(PDO::FETCH_ASSOC);
$recent = array_filter($rows, fn($r) => $r["OrderDate"] > "2026-01-01");
// Fast: filters on the server
$stmt = $conn->prepare("SELECT OrderID, CustomerID, Total FROM dbo.Orders WHERE OrderDate > ?");
$stmt->execute(["2026-01-01"]);
$recent = $stmt->fetchAll(PDO::FETCH_ASSOC);
Paginera stora resultatuppsättningar
För en listvy som visar några hundra rader av miljoner, returnera inte alla rader och låt klienten sortera ut det. Använd serversidsidig paginering med OFFSET ... FETCH:
<?php
function fetchPage(PDO $conn, int $page, int $pageSize): array {
$stmt = $conn->prepare(
"SELECT OrderID, CustomerID, Total
FROM dbo.Orders
ORDER BY OrderID
OFFSET ? ROWS FETCH NEXT ? ROWS ONLY"
);
// With native prepares, execute([...]) binds values as strings.
// OFFSET and FETCH NEXT require integer bindings; bind explicitly.
$stmt->bindValue(1, ($page - 1) * $pageSize, PDO::PARAM_INT);
$stmt->bindValue(2, $pageSize, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
Välj rätt metod för hämtning
- Använd
fetch(PDO::FETCH_ASSOC)i en loop för streamingiteration när du inte behöver alla rader i minnet samtidigt. - Använd
fetchAll(PDO::FETCH_ASSOC)när anroparen verkligen behöver hela uppsättningen (till exempel renderar ett fullständigt JSON-svar). - Använd
fetchColumn()när du bara bryr dig om en enda skalär (enCOUNT,SUM, ellerMAX). - Använd
PDO::FETCH_KEY_PAIRellerPDO::FETCH_UNIQUEför att bygga uppslagsordböcker utan en andra genomgång.
Numeriska hämtningslägen (PDO::FETCH_NUM) är marginellt snabbare än associativa hämtningslägen eftersom de hoppar över att bygga kolumnnamnskartan. Föredra tydlighet; byt bara när ett profileringsverktyg visar att omkostnaderna för hämtning är betydande.
Föredrar SET NOCOUNT ON i lagrade procedurer och batcher
Varje INSERT-, UPDATE- och DELETE-sats returnerar en DONE_IN_PROC-token med antalet påverkade rader, som PHP vanligtvis ignorerar. Tokenet innebär inte någon tur och retur, men varje sådant kostar ändå byte på tråden och lite arbete i drivrutinen. I en procedur med flera satser eller en batch som kör hundratals satser per anrop blir besparingarna betydande. Stäng av den:
CREATE OR ALTER PROCEDURE dbo.ProcessOrder
@OrderID INT
AS
BEGIN
SET NOCOUNT ON;
UPDATE dbo.Inventory SET Stock = Stock - 1 WHERE ProductID IN (SELECT ProductID FROM dbo.OrderLines WHERE OrderID = @OrderID);
UPDATE dbo.Orders SET Status = 'Processed' WHERE OrderID = @OrderID;
END;
Infoga data effektivt
Välj rätt insättningsmetod baserat på hur många rader du flyttar. Fel val kan vara 100 gånger långsammare.
Färre än cirka 100 rader: förberedd sats i en loop
För små omgångar, exekvera en enda förberedd instruktion i en loop:
<?php
$stmt = $conn->prepare("INSERT INTO dbo.Products (Name, Price) VALUES (?, ?)");
foreach ($products as $p) {
$stmt->execute([$p["name"], $p["price"]]);
}
Slå in loopen i en transaktion så att alla inserts commitar som en enhet och loggen inte behöver flushas efter varje rad:
<?php
$conn->beginTransaction();
try {
$stmt = $conn->prepare("INSERT INTO dbo.Products (Name, Price) VALUES (?, ?)");
foreach ($products as $p) {
$stmt->execute([$p["name"], $p["price"]]);
}
$conn->commit();
} catch (PDOException $e) {
$conn->rollBack();
throw $e;
}
Hundratals till miljontals rader: tabellvärda parametrar
Tabellvärdesparametrar (TVP) skickar hela batchen till SQL Server i en enda tur och retur och låter SQL Server bearbeta uppsättningen i en enda sats. För batchar med hundratals rader eller fler är TVP:er vanligtvis mycket snabbare än en förberedd statement-loop och de skalar linjärt med radantalet.
Först, skapa en tabelltyp på servern:
CREATE TYPE dbo.ProductTableType AS TABLE (
Name NVARCHAR(100),
Price DECIMAL(10, 2)
);
PDO_SQLSRV skickar TVP:n som en associativ matris där nyckeln är typnamnet och värdet är raduppsättningen. Bind den med PDO::PARAM_LOB:
<?php
$rows = [];
foreach ($products as $p) {
$rows[] = [$p["name"], $p["price"]];
}
$tvpInput = ["ProductTableType" => $rows];
$stmt = $conn->prepare(
"INSERT INTO dbo.Products (Name, Price) SELECT Name, Price FROM ?"
);
$stmt->bindParam(1, $tvpInput, PDO::PARAM_LOB);
$stmt->execute();
För ett icke-standardschema, skicka schemat som arrayens nästa element: ["ProductTableType" => $rows, "Sales"]. För exempel på SQLSRV:s procedursyntax och lagrade procedurer, se Använd tabellvärda parametrar.
Miljontals rader: bcp eller BULK INSERT
För riktigt stora operationer (datalagerslaster, initiala migreringar), använd bcp eller BULK INSERT istället för PHP. Skriv data till en avgränsad fil eller en fil i internt format och kör sedan bcp eller BULK INSERT från ett schemalagt jobb, ett ETL-steg eller ett administrationsskript.
Caution
Om du anropar bcp från PHP med shell_exec() eller proc_open(), infoga aldrig opålitliga indata i kommandoraden. Använd escapeshellarg() på varje argument, och kör helst laddningen separat i stället för i sökvägen för en webbförfrågan.
Minska tur- och returresor
Varje nätverkstur och retur mellan PHP och SQL Server har en fast kostnad. När du skickar fem kontoutdrag som en batch betalar du kostnaden en gång istället för fem gånger.
Kombinera relaterade satser till en enda batch
För relaterade åtgärder som körs tillsammans lägger du instruktionerna i en batch och bearbetar varje resultatuppsättning:
<?php
$sql = "
SELECT * FROM dbo.Customers WHERE CustomerID = ?;
SELECT * FROM dbo.Orders WHERE CustomerID = ?;
SELECT * FROM dbo.Addresses WHERE CustomerID = ?;
";
$stmt = $conn->prepare($sql);
$stmt->execute([$id, $id, $id]);
$customer = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt->nextRowset();
$orders = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->nextRowset();
$addresses = $stmt->fetchAll(PDO::FETCH_ASSOC);
För SQLSRV, använd sqlsrv_next_result för att avancera mellan resultatuppsättningar.
Aktivera flera aktiva resultatuppsättningar när du behöver det
Multiple Active Result Sets (MARS) gör det möjligt för en enda anslutning att ha flera aktiva instruktioner. Utan MARS kan du inte göra en ny fråga på en anslutning som fortfarande har en öppen resultatuppsättning. Båda drivrutinerna aktiverar MARS som standard. För att stänga av den, ställ MultipleActiveResultSets=false in din reťazec pripojenia. Se Inaktivera flera aktiva resultatuppsättningar (MARS).
MARS är bekvämt men inte gratis. Varje aktiv resultatuppsättning förbrukar serverresurser. Bearbeta helst hela resultatuppsättningen innan du påbörjar en annan. Använd MARS för att avblockera genuint inbäddade markörmönster.
Optimera förberedda satser
Förberedda instruktioner gör att drivrutinen slipper tolka om SQL på servern, och de låter dig binda opålitliga indata till parametrar på ett säkert sätt.
Föredrar inhemska förberedelser
PDO_SQLSRV kan förbereda satser i två läge.
Native prepares skickar SQL-texten till servern en gång och återanvänder den parsade satsen för varje exekvering, och skickar endast parametervärdena på varje execute().
Emulerade förberedelser behåller SQL-texten i klienten och bygger om en fullständig SQL-sträng med parametrar interpolerade vid varje exekvering.
Ställ in PDO::ATTR_EMULATE_PREPARES => false så att föraren använder inbyggda förberedelser. Inbyggda förberedelser låter SQL Server cacha och återanvända frågeplanen, och de undviker att parsa om SQL-text vid varje körning.
<?php
$conn = new PDO($dsn, null, null, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
]);
Återanvänd förberedda uttalanden
Förbered dig en gång, avrätta många. Varje prepare() anrop medför en allokering av ett ODBC-handtag och en tolkning på serversidan. I en hetloop, håll objektet $stmt levande och anropa execute() inuti loopen:
<?php
// Fast: one prepare, many executes.
$stmt = $conn->prepare("UPDATE dbo.Inventory SET Stock = Stock - ? WHERE ProductID = ?");
foreach ($orderLines as $line) {
$stmt->execute([$line["qty"], $line["productId"]]);
}
// Slow: re-prepares the same SQL on every iteration.
foreach ($orderLines as $line) {
$stmt = $conn->prepare("UPDATE dbo.Inventory SET Stock = Stock - ? WHERE ProductID = ?");
$stmt->execute([$line["qty"], $line["productId"]]);
}
Se upp för TOP (?) och IN (?, ?, ...)
TOPkräver parenteser runt en parametermarkör, SELECT TOP (?) ..., så att SQL Server kan tolka radräkningen som en parameter.
IN (?, ?, ?, ?) kräver ett fast antal platshållare vid förberedelsetid. För dynamiska IN liststorlekar, antingen bygger platshållarsträngen från ett validerat heltalsantal eller skickar listan som en tabellvärd parameter.
Caution
Interpolera aldrig rå användarinmatning i SQL-texten (inklusive platshållarantalet). Kasta räkningen med (int) innan du bygger platshållarsträngen, och låt alltid de faktiska värdena passera execute() som parametrar.
Hantera markörer och minne
Standardtypen för pekare är PDO::CURSOR_FWDONLY, en pekare som bara kan läsas framåt. Den strömmar rader till PHP en i taget och buffrar inte, så en stor resultatmängd begränsas av radbuffertminnet istället för det totala radantalet. Det är oftast det du vill.
Använd buffrade markörer endast när du behöver gå bakåt eller räkna rader
PDO::SQLSRV_CURSOR_BUFFERED (en buffrad statisk markör på klientsidan) läser in hela resultatuppsättningen i PHP-minnet på en gång. Detta tillvägagångssätt låter dig anropa rowCount(), söka bakåt och återanvända påståendet. Som standard är bufferten begränsad till 10 240 KB (10 MB) via PDO::SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE, och en fråga vars resultatmängd överstiger taket returnerar false istället för att överfylla PHP-minnet. Du kan höja gränsen upp mot PHP:s minnesgräns, men då byter du ett false returvärde mot ett verkligt Allowed memory size exhausted fatalt fel när en fråga överskrider den nya gränsen. Justera avsiktligt. Se Markörtyper (PDO_SQLSRV).
Serversidiga rullbara markörer (PDO::SQLSRV_CURSOR_STATIC, PDO::SQLSRV_CURSOR_DYNAMIC, PDO::SQLSRV_CURSOR_KEYSET) buffrar på servern istället för klienten, så de förbrukar inte PHP-minne. De använder dock serverresurser under hela markörens livslängd och är långsammare per rad än framåtriktade markörer.
Använd standardinställningen endast framåtriktad vid strömmande läsning. Använd buffrad klientsida för små resultatuppsättningar när du behöver rowCount() eller bakåtscrollning. Undvik serversidiga scrollbara markörer om du inte gör något specifikt.
<?php
// Fast, low memory: default forward-only, one row at a time
$stmt = $conn->prepare("SELECT OrderID, Total FROM dbo.Orders");
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
// ...
}
// Buffered: only when you need rowCount() or seeking
$stmt = $conn->prepare("SELECT * FROM dbo.SmallLookup", [
PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL,
PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED,
]);
$stmt->execute();
$rowCount = $stmt->rowCount();
För en fullständig genomgång, se Cursor types (PDO_SQLSRV) och Cursor types (SQLSRV).
Strömma stora binärdata- och teckendatavärden
För varbinary(max), varchar(max),nvarchar(max), xml och andra stora typer, använd PHP-strömmar istället för att materialisera hela värdet i minnet:
<?php
$stmt = $conn->prepare("SELECT Name, PhotoBlob FROM dbo.Products WHERE ProductID = ?");
$stmt->execute([$id]);
$stmt->bindColumn("PhotoBlob", $photo, PDO::PARAM_LOB);
$stmt->fetch(PDO::FETCH_BOUND);
// $photo is a stream resource; write it directly to disk without loading it all
$outFile = fopen("/tmp/photo.bin", "wb");
stream_copy_to_stream($photo, $outFile);
fclose($outFile);
För att infoga eller uppdatera med stora värden, använd SendStreamParamsAtExec=false i SQLSRV för att skicka strömdata i block efter sqlsrv_execute(). Mer information finns i Skicka data i en ström.
Ange lämpliga tidsgränser
Tidsgränser är lika mycket prestandainställningar som inställningar för tillförlitlighet. Långhängande frågor håller poolanslutningar och svälter ut andra förfrågningar.
Utdragstidsgräns
Ange en tidsgräns för varje fråga så att en fråga som skenar inte blockerar en anslutning i anslutningspoolen på obestämd tid. För PDO_SQLSRV:
<?php
$stmt = $conn->prepare("SELECT ... FROM dbo.HugeTable ...");
$stmt->setAttribute(PDO::SQLSRV_ATTR_QUERY_TIMEOUT, 30); // seconds
$stmt->execute();
För SQLSRV, ange "QueryTimeout" => 30 i arrayen med alternativ till sqlsrv_query eller sqlsrv_prepare.
Sätt ett värde som matchar din arbetsbelastning. För en synkron webbförfrågan är 15 till 30 sekunder typiskt. För ett bakgrundsbatchjobb kan flera minuter vara rimligt. Sätt aldrig timeouten till noll (obegränsad) i en webbförfrågan.
Tidsgräns för inloggning
LoginTimeoutI reťazec pripojenia styrs hur länge drivrutinen väntar på att etablera en anslutning. Ange ett explicit värde när du ansluter till Azure SQL Database eller Azure SQL Managed Instance så att kallstarter och redundansgruppsväxlingar inte gör att klienten hänger sig på obestämd tid. Värden från 30 till 90 sekunder fungerar bra för de flesta molnarbetsbelastningar. Mer information om dimensionering av LoginTimeout i förhållande till ConnectRetryCount * ConnectRetryInterval och de fel som då kan uppstå finns i Tidsgräns för anslutning. För referensen till alternativ, se Anslutningsalternativ.
Dirigera skrivskyddade arbetsbelastningar till en replika
För skrivskyddsfrågor mot en databas i en Always On-tillgänglighetsgrupp, Azure SQL Managed Instance eller Azure SQL Database med läsningsskalning eller georeplik, lägg till ApplicationIntent=ReadOnly i din anslutningssträng:
<?php
$dsn = "sqlsrv:Server=<listener>;Database=<database>;" .
"Encrypt=true;ApplicationIntent=ReadOnly";
Skrivskyddad routing skickar anslutningen till en synkroniserad sekundär replika och avlastar arbete från den primära. Kombinera med MultiSubnetFailover=true för den snabbaste anslutningen till lyssnare för tillgänglighetsgrupper med flera undernät.
Övervaka serverns prestanda
Kundsidans timing visar bara hur lång tid en fråga tog från början till slut. För att ta reda på varför det var långsamt, använd SQL Server:s inbyggda diagnostik.
Querybutik
Query Store fångar exekveringsplaner, körstatistik och väntestatistik för varje fråga i databasen. Det är aktiverat som standard på Azure SQL Database, Azure SQL Managed Instance och SQL Database in Fabric. På SQL Server, aktivera det per databas:
ALTER DATABASE <database_name> SET QUERY_STORE = ON;
Använd sedan SQL Server Management Studio:s Query Store-rapporter för att hitta dina långsammaste och mest frekvent utförda frågor. Se Övervakning av prestanda med Query Store.
Azure SQL Query Performance Insight
För Azure SQL Database visar Azure-portalens Query Performance Insight automatiskt de mest resurskrävande frågorna utan någon konfiguration. Mer information finns i Query Performance Insight för Azure SQL Database.
SET STATISTICS för engångsutredning
För en enskild fråga som du vill profilera, kör den i SQL Server Management Studio med statistik aktiverad:
SET STATISTICS TIME ON;
SET STATISTICS IO ON;
-- your query here
Höga logiska läsningar betyder nästan alltid att indexet saknas eller inte kan användas. Hög CPU-tid med låga logiska läsningar innebär oftast en dålig plan (parametersniffing, en implicit konvertering som förhindrar indexanvändning, eller en skalär funktion som förhindrar parallellism).
Utökade evenemang för förarspårning
För att se exakt vad drivrutinen skickar till SQL Server (inklusive de faktiska parametervärdena den interpolerar), fånga en Extended Events-session genom att använda rpc_completed och sql_batch_completed händelserna.
Checklista för prestanda
Använd denna checklista som en förhandsgranskning av alla PHP-applikationer som ansluter till SQL Server:
| Area | Kontrollera | Reference |
|---|---|---|
| Connection | Anslutningspoolning är aktiverad och konfigurerad för plattformen | Hantera anslutningar effektivt |
| Connection | Applikationen återanvänder anslutningar inom en förfrågan och öppnar inte anslutningar per fråga | Återanvänd anslutningen inom en begäran |
| Connection |
LoginTimeouttäcker kallstarter och redundansväxling för Azure SQL |
Inloggningstidsavbrott |
| Query | Frågor väljer bara de kolumner som behövs, nej SELECT * |
Välj endast de kolumner du använder |
| Query | Filtrering sker i SQL, inte i PHP med array_filter |
Hämta bara de rader du behöver |
| Query | Stora resultatmängder är paginerade med OFFSET ... FETCH |
Sidindela stora resultatmängder |
| Query | Lagrade procedurer, uppsättning SET NOCOUNT ON |
Föredra SET NOCOUNT ON |
| Infogningar | Bulkinsatser använder tabellvärda parametrar, inte per-rad-loopar | Infoga data effektivt |
| Utdrag |
PDO::ATTR_EMULATE_PREPARES är inställt på false |
Föredrar inhemska förberedelser |
| Utdrag | Applikationen återanvänder förberedda SQL-satser mellan körningar | Återanvänd förberedda uttalanden |
| Cursors | Applikationen använder standardmarkören som endast är framåtriktad om inte buffring behövs | Hantera markörer och minne |
| Memory | Stora binär- och teckenvärden strömmas, inte materialiseras | Strömma stora binära värden och teckendata |
| Timeouts | Tidsavgränsning för ett uttalande är satt på alla användarvända frågor | Statement timeout |
| Routing | Skrivskyddade arbetsbelastningar ställs in på ApplicationIntent=ReadOnly där det finns en replika |
Dirigera skrivskyddade arbetslaster |
| Observability | Query Store är aktiverad och granskas regelbundet | Query Store |