Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Dit artikel behandelt hoe je snelle PHP-code schrijft tegen SQL Server, Azure SQL Database, Azure SQL Managed Instance, Azure Synapse Analytics en SQL Database in Microsoft Fabric. De richtlijnen gelden voor zowel SQLSRV als PDO_SQLSRV, die dezelfde onderliggende Microsoft ODBC-driver voor SQL Server omwikkelen.
Begin met de veranderingen met de grootste impact
Als je maar drie wijzigingen kunt aanbrengen, doe dan deze:
- Schakel verbindingspooling in. Het opzetten van een nieuwe TLS-verbinding met SQL Server duurt tientallen tot honderden milliseconden, afhankelijk van het netwerkpad en TLS-onderhandeling. Het hergebruiken van gepoolde verbindingen elimineert die kosten per verzoek. Zie Verbindingen efficiënt beheren.
- Haal alleen de kolommen en rijen die je nodig hebt.
SELECT *en onbegrensde queries zijn de meest voorkomende oorzaken van trage eindpunten. Zie Alleen zoeken wat je nodig hebt. - Gebruik tabel-waarde parameters voor bulk-inserts. Voor honderden rijen of meer zijn tabel-gewaardeerde parameters (TVP's) doorgaans veel sneller dan rij-voor-rij
INSERTstatements en schalen ze lineair met het aantal rijen. Zie Data efficiënt invoegen.
Beheer verbindingen efficiënt
Het tot stand brengen van verbindingen is de duurste handeling die de bestuurder uitvoert. Bijna elk PHP-prestatieonderzoek eindigt met een oplossing voor verbindingsbeheer.
Groepsgewijze verbindingen inschakelen
Pooling hergebruikt ODBC-verbindingen over PHP-verzoeken in plaats van ze aan het einde van het verzoek af te breken. Het verbindingsobject wordt verwijderd wanneer je script eindigt, maar de onderliggende ODBC-handle blijft actief in de pool van de ODBC-drivermanager en wordt hergebruikt door het volgende verzoek dat om dezelfde verbindingsreeks vraagt.
Windows: Connection pooling staat standaard aan. Om het te bevestigen, laat de ConnectionPooling optie weg in je DSN. Om pooling voor debugging uit te schakelen, stel ConnectionPooling=0je .
Linux en macOS: Connection pooling is geen DSN-optie op deze platforms. Schakel het in in de driver manager door in het gedeelte van odbcinst.iniin te [ODBC] stellenPooling=Yes, en zet een positief CPTimeout onder de strofe van de driver. Voorbeeld:
[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
Vind het daadwerkelijke bibliotheekpad met odbcinst -q -d -n "ODBC Driver 18 for SQL Server" of ls /opt/microsoft/msodbcsql18/lib64/. De bestandsnaam bevat de geïnstalleerde ODBC-driverversie en verandert bij elke release.
CPTimeout (in seconden) bepaalt hoe lang de stationaire verbindingen in het zwembad blijven voordat ze worden gesloten. Stel het hoog genoeg in zodat de meeste verzoeken een gepoolde verbinding vinden, maar laag genoeg zodat verouderde verbindingen met een failover-server redelijk snel worden beëindigd. 60 tot 300 seconden werkt goed voor de meeste webworkloads.
Voor details, zie Verbindingspooling.
Begrijp de kosten van de eerste zoekopdracht
Multiple Active Result Sets (MARS) is standaard ingeschakeld. Wanneer MARS en connection pooling beide actief zijn, reset de driver de gepoolde verbinding bij de eerste query, en die reset negeert elke query-timeout die je voor die eerste query hebt ingesteld. Latere zoekopdrachten op dezelfde verbinding erkennen normaal gesproken de time-out. Als je agressieve timeouts voor eerste query instelt op een gepoolde workload, houd dan rekening met dit gedrag, of schakel MARS uit MultipleActiveResultSets=false als je het niet nodig hebt. Zie de MARS- en poolingnotitie in Connection pooling.
Persistente PDO-verbindingen worden niet ondersteund
PDO_SQLSRV wijst PDO::ATTR_PERSISTENTaf. Het op de constructor throws zetten:
SQLSTATE[IMSSP]: An unsupported attribute was designated on the PDO object.
Gebruik ODBC connection pooling voor cross-request hergebruik. Het is het driver-native mechanisme, werkt zowel voor PDO_SQLSRV als SQLSRV, en zet idle-verbindingen aan CPTimeout (wat ook Microsoft Entra tokenverversing eerlijk houdt).
Hergebruik de verbinding binnen een verzoek
Zelfs met pooling veroorzaakt het openen van een nieuwe PDO- of SQLSRV-verbinding een ODBC-retour om een gepoolde handle op te halen en te valideren. Open één keer per verzoek een verbinding en geef die door aan elke functie die die nodig heeft.
Tip
Een afhankelijkheidsinjectiecontainer of een luie accessor is voldoende. Het punt is om midden in een request handler te vermijden new PDO(...) .
Vraag alleen wat je nodig hebt
Netwerk-rondreizen en materialisatie van resultaatsets domineren de querylatentie voor de meeste PHP-workloads. De fixes zijn dezelfde die op elke databasetoegangslaag gelden.
Selecteer alleen de kolommen die je gebruikt
SELECT * Trekt elke kolom, inclusief varchar(max) en varbinary(max) kolommen die de data die je daadwerkelijk consumeert veel overtreft. Noem de kolommen:
<?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");
Haal alleen de rijen die je nodig hebt
Push filtering naar SQL Server. Haal nooit een volledige tabel in PHP om in een foreach lus te filteren.
<?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);
Grote resultatensets pagineren
Voor een lijstweergave die een paar honderd rijen uit miljoenen toont, stuur niet alle rijen terug en laat de klant het zelf uitzoeken. Gebruik server-side paginering met 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);
}
Kies de juiste haalmethode
- Gebruik
fetch(PDO::FETCH_ASSOC)in een loop voor streamingiteratie wanneer je niet alle rijen tegelijk in het geheugen nodig hebt. - Gebruik
fetchAll(PDO::FETCH_ASSOC)wanneer de caller echt de hele set nodig heeft (bijvoorbeeld het renderen van een volledige JSON-respons). - Gebruik
fetchColumn()wanneer je maar om één scalair geeft (aCOUNT,SUM, ofMAX). - Gebruik
PDO::FETCH_KEY_PAIRofPDO::FETCH_UNIQUEbouw opzoekwoordenboeken zonder een tweede doorgang.
Numerieke fetch-modi (PDO::FETCH_NUM) zijn marginaal sneller dan associatieve fetch-modi omdat ze het bouwen van de kolomnaammap overslaan. Geef de voorkeur aan duidelijkheid; Schakel alleen over wanneer een profiler fetch-overhead als significant markeert.
Geef voorkeur SET NOCOUNT ON aan opgeslagen procedures en batches
Elke INSERT, , and-instructie UPDATEDELETE geeft een DONE_IN_PROC token met het getroffen aantal rijen terug, dat PHP doorgaans weggooit. De token voegt geen heen-en-terug toe, maar elke token kost nog steeds bytes op de kabel en een kleine hoeveelheid driverwerk. In een multi-statement procedure of batch die honderden statements per call uitvoert, lopen de besparingen op. Zet het uit:
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;
Efficiënt gegevens invoegen
Kies de juiste inzetmethode op basis van hoeveel rijen je verplaatst. De verkeerde keuze kan honderd keer langzamer zijn.
Minder dan ongeveer 100 rijen: voorbereide verklaring in een lus
Voor kleine batches voer je een enkele voorbereide instructie uit in een lus:
<?php
$stmt = $conn->prepare("INSERT INTO dbo.Products (Name, Price) VALUES (?, ?)");
foreach ($products as $p) {
$stmt->execute([$p["name"], $p["price"]]);
}
Wikkel de lus in een transactie zodat alle inserts als één eenheid committen en het logboek niet na elke rij hoeft te flushen:
<?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;
}
Honderden tot miljoenen rijen: tabelwaardige parameters
Tabel-waardige parameters (TVP's) sturen de volledige batch in één ronde naar SQL Server en laten SQL Server de set als één enkele instructie verwerken. Voor batches van honderden rijen of meer zijn TVP's doorgaans veel sneller dan een prepared-statement-lus en schalen ze lineair met het aantal rijen.
Maak eerst een tabeltype aan op de server:
CREATE TYPE dbo.ProductTableType AS TABLE (
Name NVARCHAR(100),
Price DECIMAL(10, 2)
);
PDO_SQLSRV geeft de TVP door als een associatieve array waarvan de sleutel de typenaam is en waarvan de waarde de rijset is. Bind het met 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();
Voor een niet-standaard schema geef je het schema door als het volgende element van de array: ["ProductTableType" => $rows, "Sales"]. Voor de SQLSRV-procedurele syntaxis en voorbeelden van opgeslagen procedures, zie Gebruik tabel-waardige parameters.
Miljoenen rijen: bcp of BULK INSERT
Voor echt bulkoperaties (data warehouse-loads, initiële migraties), gebruik bcp of BULK INSERT in plaats van PHP. Schrijf je data naar een gescheiden of native-formaat bestand, en voer dan bcp uit of BULK INSERT vanuit een geplande taak, ETL-stap of adminscript.
Caution
Als je vanuit PHP shell_exec() met of proc_open()naar BCP betaalt, interpoleer dan nooit onbetrouwbare invoer in de commandoregel. Gebruik escapeshellarg() het op elk argument, en geef de voorkeur aan het uitvoeren van de load out-of-band in plaats van in een webrequest-pad.
Verminder retourreizen
Elke netwerk-heen-en-weer tussen PHP en SQL Server heeft een vaste kosten. Wanneer je vijf afschriften in één batch verstuurt, betaal je die kosten één keer in plaats van vijf keer.
Combineer gerelateerde statements tot één batch
Voor gerelateerd werk dat samen draait, zet je de statements in één batch en gebruik je elke resultaatset:
<?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);
Voor SQLSRV gebruik sqlsrv_next_result je om tussen resultaatsets te doorgaan.
Schakel meerdere actieve resultaatsets in wanneer je dat nodig hebt
Multiple Active Result Sets (MARS) laat een enkele verbinding meerdere actieve statements hebben. Zonder MARS kun je geen nieuwe query uitvoeren op een verbinding die nog steeds een open resultaatset heeft. Beide drivers schakelen MARS standaard in. Om het uit te schakelen, zet MultipleActiveResultSets=false je je verbindingsreeks in. Zie Meerdere actieve resultaatsets (MARS) uitschakelen.
MARS is handig maar niet gratis. Elke actieve resultaatset verbruikt server-side resources. Geef de voorkeur aan een volledige resultatenset voordat je aan een nieuwe begint. Gebruik MARS om echt geneste cursorpatronen te deblokkeren.
Toon bereidde verklaringen voor
Prepared statements besparen de driver van het opnieuw parsen van SQL op de server, en ze laten je onbetrouwbare invoer veilig als parameters binden.
Geef de voorkeur aan inheemse bereidingen
PDO_SQLSRV kunnen statements in twee modi voorbereiden.
Native pres sturen de SQL-tekst één keer naar de server en hergebruiken de geparseerde instructie voor elke uitvoering, waarbij alleen de parameterwaarden op elke execute().
Geëmuleerde voorbereidingen houden de SQL-tekst in de client en bouwen een volledige SQL-string opnieuw met parameters die bij elke uitvoering worden geïnterpoleerd.
Stel het zo in PDO::ATTR_EMULATE_PREPARES => false dat de driver native prepares gebruikt. Native prepares laten SQL Server het queryplan cachen en hergebruiken, en ze vermijden het opnieuw parsen van SQL-tekst bij elke uitvoering.
<?php
$conn = new PDO($dsn, null, null, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
]);
Hergebruik voorbereide statements
Bereid één keer voor, voer er vele uit. Elke prepare() oproep kost een ODBC-handle allocation en een server-side parse. In een hot loop houd je het $stmt object levend en roep execute() je binnen de lus aan:
<?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"]]);
}
Let op en TOP (?)IN (?, ?, ...)
TOPvereist haakjes rond een parametermarker, SELECT TOP (?) ..., zodat SQL Server het aantal rijen als parameter kan parsen.
IN (?, ?, ?, ?) vereist een vaste plaatshoudende telling bij de voorbereiding. Voor dynamische IN lijstgroottes bouwt u ofwel de tijdelijke string uit een gevalideerde gehele telling, of geeft u de lijst door als een tabelwaardige parameter.
Caution
Interpolleer nooit ruwe gebruikersinvoer in de SQL-tekst (inclusief het aantal tijdelijke gebruikers). Spreek de telling uit met (int) voordat je de tijdelijke string bouwt, en geef altijd de daadwerkelijke waarden als parameters door.execute()
Cursors en geheugen beheren
Het standaard cursortype is PDO::CURSOR_FWDONLY, een alleen vooruitgestuurde brandslang. Het streamt rijen één voor één naar PHP en buffert niet, dus een grote set resultaten wordt begrensd door het rij-buffergeheugen in plaats van het totale aantal rijen. Dat is meestal wat je wilt.
Gebruik gebufferde cursors alleen wanneer je achteruit moet gaan of rijen moet tellen
PDO::SQLSRV_CURSOR_BUFFERED (een client-side gebuffde statische cursor) haalt de volledige resultaatset direct in het PHP-geheugen. Deze aanpak stelt je in staat om de uitspraak aan te roepen rowCount(), achteruit te zoeken en te hergebruiken. Standaard is de buffer gelimiteerd op 10.240 KB (10 MB) via PDO::SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE, en een query waarvan de resultaatset de limiet overschrijdt, geeft terug false in plaats van PHP-geheugen te overlopen. Je kunt de limiet verhogen richting de PHP-geheugenlimiet, maar dat ruilt een false return in voor een echt Allowed memory size exhausted fatale fout wanneer een query de nieuwe limiet overschrijdt. Stem bewust af. Zie Cursortypes (PDO_SQLSRV).
Server-side scrollbare cursors (PDO::SQLSRV_CURSOR_STATIC, PDO::SQLSRV_CURSOR_DYNAMIC, ) PDO::SQLSRV_CURSOR_KEYSETbufferen op de server in plaats van op de client, zodat ze geen PHP-geheugen verbruiken. Ze houden echter server-side resources vast gedurende de duur van de cursor en zijn per rij trager dan alleen vooruit-gebaseerde bronnen.
Gebruik de standaard forward-only voor het streamen van lezen. Gebruik gebufferde client-side voor kleine resultaatsets wanneer je dat nodig hebt rowCount() , of achterwaarts scrollen. Vermijd server-side scrollbare cursors, tenzij je iets specifieks doet.
<?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();
Voor een volledige overzicht, zie Cursortypes (PDO_SQLSRV) en Cursor types (SQLSRV).
Stroom grote binaire en tekenwaarden
Voor varbinary(max),varchar(max),nvarchar(max), xml en andere grote types, gebruik PHP-stromen in plaats van de volledige waarde in het geheugen te materialiseren:
<?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);
Voor het invoegen of updaten met grote waarden, gebruik SendStreamParamsAtExec=false in SQLSRV om stroomdata in chunks na sqlsrv_execute()te sturen. Voor details, zie Gegevens als stroom verzenden.
De juiste time-outs instellen
Time-outs zijn net zo goed prestatie-instellingen als betrouwbaarheidsinstellingen. Langhangende zoekopdrachten houden poolverbindingen vast en verhongeren andere verzoeken.
Time-out voor instructie
Stel een tijdslimiet per instructie in zodat een runaway-query geen poolverbinding oneindig vasthoudt. Voor PDO_SQLSRV:
<?php
$stmt = $conn->prepare("SELECT ... FROM dbo.HugeTable ...");
$stmt->setAttribute(PDO::SQLSRV_ATTR_QUERY_TIMEOUT, 30); // seconds
$stmt->execute();
Voor SQLSRV geef "QueryTimeout" => 30 je de optiesarray in naar sqlsrv_query of sqlsrv_prepare.
Stel een waarde in die past bij je werkdruk. Voor een synchrone webaanvraag is 15 tot 30 seconden typisch. Voor een achtergrondbatch kunnen enkele minuten redelijk zijn. Stel de timeout nooit in op nul (onbeperkt) bij een webverzoek.
Time-out voor aanmelden
LoginTimeoutIn de verbindingsreeks wordt bepaald hoe lang de driver wacht om een verbinding tot stand te brengen. Stel een expliciete waarde in bij het verbinden met Azure SQL Database of Azure SQL Managed Instance zodat cold starts en failover-group failovers de client niet oneindig vastlopen. Waarden van 30 tot 90 seconden werken goed voor de meeste cloudworkloads. Voor details over het dimensioneren LoginTimeout tegenover ConnectRetryCount * ConnectRetryInterval en de resulterende faalmodi, zie Verbindingstimeout. Voor de referentie voor de optie, zie Verbindingsopties.
Route alleen-lezen workloads naar een replica
Voor alleen-lezen queries tegen een database in een Always On-beschikbaarheidsgroep, Azure SQL Managed Instance of Azure SQL Database met een read scale-out of geo-replica, voeg ApplicationIntent=ReadOnly je toe aan je verbindingsreeks:
<?php
$dsn = "sqlsrv:Server=<listener>;Database=<database>;" .
"Encrypt=true;ApplicationIntent=ReadOnly";
Alleen-lezen routering stuurt de verbinding naar een gesynchroniseerde secundaire replica, waarbij het werk wordt afgelast. Combineer met MultiSubnetFailover=true voor de snelste verbinding met luisteraars in de multi-subnet beschikbaarheidsgroep.
Bekijk de prestaties vanaf de server
De timing aan de clientzijde vertelt alleen hoe lang een query van begin tot eind duurde. Om te achterhalen waarom het traag was, gebruik je de ingebouwde diagnostiek van SQL Server.
Querywinkel
Query Store legt uitvoeringsplannen, runtime-statistieken en wachtstatistieken vast voor elke query in de database. Het is standaard ingeschakeld op Azure SQL Database, Azure SQL Managed Instance en SQL Database in Fabric. Op SQL Server schakel je het per database in:
ALTER DATABASE <database_name> SET QUERY_STORE = ON;
Gebruik vervolgens de Query Store-rapporten van SQL Server Management Studio om je langzaamste en meest uitgevoerde queries te vinden. Zie Prestaties monitoren met de Query Store.
Azure SQL Query Performance Insight
Voor Azure SQL Database toont de Query Performance Insight van het Azure-portaal automatisch de meest resource-verbruikende queries zonder enige configuratie. Zie Query Performance Insight voor Azure SQL Database voor meer informatie.
SET STATISTICS voor eenmalig onderzoek
Voor een enkele query die je wilt profileren, voer deze uit in SQL Server Management Studio met statistieken ingeschakeld:
SET STATISTICS TIME ON;
SET STATISTICS IO ON;
-- your query here
Hoge logische reads betekenen bijna altijd een ontbrekende of onbruikbare index. Hoge CPU-tijd bij weinig logische reads betekent meestal een slecht plan (parametersniffing, een impliciete conversie die indexgebruik voorkomt, of een scalaire functie die parallelisme voorkomt).
Uitgebreide evenementen voor traceren op rijdersniveau
Om precies te zien wat de driver naar SQL Server stuurt (inclusief de daadwerkelijke parameterwaarden die hij interpoleert), leg een Extended Events-sessie vast door gebruik te maken van de rpc_completed en sql_batch_completed events.
Controlelijst voor prestaties
Gebruik deze checklist als pre-deployment review van elke PHP-applicatie die verbinding maakt met SQL Server:
| Gebied | Selecteren | Reference |
|---|---|---|
| Connection | Connection pooling is ingeschakeld en geconfigureerd voor het platform | Beheer verbindingen efficiënt |
| Connection | De applicatie hergebruikt verbindingen binnen een verzoek en opent geen verbindingen per query | Hergebruik de verbinding binnen een verzoek |
| Connection |
LoginTimeoutbehandelt cold starts en failover voor Azure SQL |
Inlogtime-out |
| Query | Queries selecteren alleen de benodigde kolommen, nee SELECT * |
Selecteer alleen de kolommen die je gebruikt |
| Query | Filteren gebeurt in SQL, niet in PHP met array_filter |
Haal alleen de rijen die je nodig hebt |
| Query | Grote resultaatsets zijn gepagineerd met OFFSET ... FETCH |
Paginate grote resultaatsets |
| Query | Opgeslagen proceduresset SET NOCOUNT ON |
Prefereren SET NOCOUNT ON |
| Invoegingen | Bulkinserts gebruiken tabelwaardige parameters, geen per-rij lussen | Efficiënt gegevens invoegen |
| Statements |
PDO::ATTR_EMULATE_PREPARES is ingesteld op false |
Geef de voorkeur aan inheemse bereidingen |
| Statements | De applicatie hergebruikt voorbereide statements over uitvoeringen heen | Hergebruik voorbereide statements |
| Cursors | De applicatie gebruikt de standaard forward-only cursor, tenzij buffering nodig is | Cursors en geheugen beheren |
| Memory | Grote binaire en tekenwaarden worden gestreamd, niet gematerialiseerd | Stroom grote binaire en tekenwaarden |
| Timeouts | Statement-timeout is ingesteld op alle gebruikersgerichte queries | Statement time-out |
| Routebepaling | Alleen-lezen workloads worden ingesteld ApplicationIntent=ReadOnly waar een replica bestaat |
Routeren alleen-lezen workloads |
| Observability | Query Store is ingeschakeld en regelmatig beoordeeld | Query Store |