Prestandajustering för Microsoft Drivers för PHP för SQL Server

Ladda ned PHP-drivrutin

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 Sökfråga endast 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 INSERT och 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 över PHP-förfrågningar istället för att ta ner dem vid begäran. Anslutningsobjektet kasseras när ditt skript avslutas, men det underliggande ODBC-handtaget förblir levande i ODBC-drivrutinschefens pool och återanvänds av nästa förfrågan som ber om samma reťazec pripojenia.

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 förarhanteraren genom att sätta Pooling=Yes i [ODBC] avsnittet , odbcinst.inioch sätt ett positivt CPTimeout under förarens strof. 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 (på sekunder) styr hur länge vilo-anslutningar stannar 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 frågor på samma anslutning godkänner timeouten som vanligt. Om du sätter aggressiva första-fråge-timeouts på en poolad arbetsbelastning, ta hänsyn till detta beteende, eller inaktivera MARS om MultipleActiveResultSets=false du inte behöver det. Se MARS- och poolanteckningen under Connection pooling.

Persistenta PDO-anslutningar stöds inte

PDO_SQLSRV avvisar PDO::ATTR_PERSISTENT. Att sätta den på konstruktörens kast:

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 drivrutins-inbyggda mekanism, fungerar för både PDO_SQLSRV och SQLSRV, och stänger av inaktiva anslutningar (CPTimeoutvilket också håller Microsoft Entra tokenuppdatering ärlig).

Å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 att hamna new PDO(...) mitt i en request-hanterare.

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 * Drar varje kolumn, inklusive varchar(max) och varbinär(max) kolumner som överträffar den data du faktiskt konsumerar. 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 hämtmetod

  • 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 (en COUNT, SUM, eller MAX).
  • Använd PDO::FETCH_KEY_PAIR eller PDO::FETCH_UNIQUE bygg 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 klarhet; Byt bara när en profilerare flaggar fetch-överhead som signifikant.

Föredrar SET NOCOUNT ON i lagrade procedurer och batcher

Varje INSERT, UPDATE, and-sats DELETE returnerar en DONE_IN_PROC token med den berörda radräkningen, som PHP vanligtvis kasserar. Token lägger inte till en rundresa, men varje token kostar ändå bytes på ledningen och en liten mängd drivrutinsarbete. I en multi-statement procure eller batch som kör hundratals statements per samtal blir besparingarna mycket besparingar. 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å batcher, kör en enda förberedd sats 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ärda parametrar (TVP) skickar hela batchen till SQL Server i en rundresa och låter SQL Server bearbeta mängden som 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 passerar TVP som en associativ array vars nyckel är typnamnet och vars värde är radmängden. 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 din data till en avgränsad eller native-formatfil, kör sedan bcp eller BULK INSERT från ett schemalagt jobb, ETL-steg eller adminskript.

Caution

Om du betalar för att bcp från PHP med shell_exec() eller proc_open(), interpolera aldrig opålitlig input till kommandoraden. Använd escapeshellarg() på varje argument, och föredrar att köra loaden utanför bandet istället för i 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.

För relaterat arbete som körs tillsammans, lägg satserna i en batch och konsumera 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) låter en enda anslutning ha flera aktiva satser. 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. Föredra att äta en fullständig resultatuppsättning innan du börjar en ny. Använd MARS för att avblockera genuint inbäddade markörmönster.

Melodins förberedda uttalanden

Förberedda satser sparar drivrutinen från att parsa om SQL på servern, och de låter dig säkert binda icke-betrodda indata som parametrar.

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() samtal kostar en ODBC-handtagsallokering och en server-side parse. 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 av markör är PDO::CURSOR_FWDONLY, en eldslang endast 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 klient-sida buffrad statisk markör) hämtar hela resultatuppsättningen i PHP-minnet direkt. 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 taket mot PHP-minnesgränsen, men att göra det byter en false avkastning mot ett riktigt Allowed memory size exhausted fatalt fel när en fråga växer över det nya taket. Stämm medvetet. Se Cursortyper (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 håller dock serverresurser under hela markörens varaktighet och är långsammare per rad än endast framåtriktade datorer.

Använd standardframöver-endast för strömmande läsningar. 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öm stora binära värden och teckenvä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(). För detaljer, se Skicka data som en ström.

Ange lämpliga tidsgränser

Timeouts är prestandainställningar lika mycket som tillförlitlighetsinställningar. Långhängande frågor håller poolanslutningar och svälter ut andra förfrågningar.

Utdragstidsgräns

Sätt en tidsgräns per sats så att en runaway-fråga inte håller poolanslutningen 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, skicka "QueryTimeout" => 30 in optionsarrayen 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. Sätt ett explicit värde när du ansluter till Azure SQL Database eller Azure SQL Managed Instance så att kalla starter och failover-group failovers inte fastnar klienten på obestämd tid. Värden från 30 till 90 sekunder fungerar bra för de flesta molnarbetsbelastningar. För detaljer om storlek LoginTimeout mot ConnectRetryCount * ConnectRetryInterval och de resulterande fellägena, se Anslutningstidsavslutning. För referensen till alternativ, se Anslutningsalternativ.

Dirigera skrivskyddade arbetsbelastningar till en replika

För skrivskyddade frågor mot en databas i en Always On-tillgänglighetsgrupp, Azure SQL Managed Instance eller Azure SQL Database med lässkalering eller geo-replik, lägg till ApplicationIntent=ReadOnly i din reťazec pripojenia:

<?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 snabbast anslutning till multi-subnet tillgänglighetsgrupper.

Observera 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 kalla starter och failover 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 Stora resultatmängder för sidor
Query Lagrade procedurer set 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 satser över 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öm stora binära värden och teckenvärden
Timeouts Tidsavgränsning för ett uttalande är satt på alla användarvända frågor Statement timeout
Routing Skrivskyddade arbetsbelastningar satta ApplicationIntent=ReadOnly där en replika finns Rutta lässkyddade arbetsbelastningar
Observability Query Store är aktiverad och granskas regelbundet Query Store