Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ez a cikk bemutatja, hogyan írjunk gyors PHP kódot SQL Server, Azure SQL Database, Azure SQL Managed Instance, Azure Synapse Analytics és SQL database ellen a Microsoft Fabric-ben. Az útmutatás mind az SQLSRV-re, mind a PDO_SQLSRV-re vonatkozik, amelyek ugyanazt a mögöttes Microsoft ODBC Driver for SQL Server illesztőprogramot burkolják.
Kezdjük a legnagyobb hatású változtatásokkal
Ha csak három változtatást tudsz végrehajtani, akkor ezeket a változtatásokat hozzuk:
- Engedélyezze a kapcsolatösszevonást. Egy új TLS kapcsolat létrehozása az SQL Server-hez több tíz, vagy akár több száz milliszekundig tart, attól függően, hogy milyen a hálózati útvonal és a TLS tárgyalás. A pooled kapcsolatok újrafelhasználása megszünteti ezt a költséget kérésenként. Lásd : Kapcsolatok hatékony kezelése.
- Csak azokat az oszlopokat és sorokat hozd be, amikre szükséged van.
SELECT *és a korlátlan lekérdezések a lassú végpontok leggyakoribb okai. Lásd: Csak azt kérdezd le, amire szükséged van. - Táblaértékű paramétereket használj tömeges beillesztésekhez. Több száz sor vagy több esetén a táblázatértékű paraméterek (TVP-k) általában sokkal gyorsabbak, mint a soronkénti
INSERTállítások, és lineárisan skálázódnak a sorszámmal. Lásd: Az adatok hatékony beszúrása.
Kapcsolatok hatékony kezelése
A kapcsolat létrehozása a legdrágább művelet, amit a meghajtó végez. Szinte minden PHP teljesítményvizsgálat egy kapcsolatkezelési javítással végződik.
Kapcsolatkészletezés engedélyezése
A pooling ODBC kapcsolatokat használja újra a PHP kérések között, ahelyett, hogy a kérés végén lebontaná őket. A kapcsolatobjektum eltűnik, amikor a szkript véget ér, de az alatta lévő ODBC handle életben marad az ODBC driver manager pooljában, és a következő kérés újra felhasználja, amely ugyanazt a kapcsolati karakterlánc-et kéri.
Windows: A kapcsolat pooling alapértelmezetten be van kapcsolva. A megerősítéshez hagyd ki ezt ConnectionPooling a lehetőséget a DSN-edből. A pooling hibakereséshez történő letiltásához állítsa be a(z) ConnectionPooling=0 értéket.
Linux és macOS: Ezeken a platformokon a kapcsolat pooling nem DSN opció. Engedélyezd az illesztőprogram-kezelőben úgy, hogy a(z) odbcinst.ini[ODBC] szakaszában beállítod a(z) Pooling=Yes értéket, és az illesztőprogram szakaszában a(z) CPTimeout értékét pozitívra állítod. Például:
[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
Találd meg a tényleges könyvtári útvonalat az odbcinst -q -d -n "ODBC Driver 18 for SQL Server" vagy ls /opt/microsoft/msodbcsql18/lib64/-vel . A fájlnév beágyazza az telepített ODBC illezőprogram-verziót, és minden kiadással változik.
CPTimeout (másodpercek alatt) szabályozza, mennyi ideig maradnak az alapjárati kapcsolatok a medencében, mielőtt bezárnák. Állítsd elég magasra ahhoz, hogy a legtöbb kérés összekötött kapcsolatot találjon, de elég alacsonyra ahhoz, hogy a hibás szerverhez tartozó elavult kapcsolatok viszonylag gyorsan eltűnjenek. 60-300 másodperc a legtöbb webes munkaterhelésnél jól működik.
Részletekért lásd: Kapcsolati csoportosítás.
Értsd meg az első lekérdezés költségét
Alapértelmezés szerint több aktív eredményhalmaz (MARS) van engedélyezve. Ha mind a MARS, mind a kapcsolat-összevonás aktív, az illesztőprogram az első lekérdezéskor alaphelyzetbe állítja a készletből származó kapcsolatot, és ez a visszaállítás figyelmen kívül hagyja az első lekérdezéshez beállított lekérdezési időkorlátot. Az ugyanazon a kapcsolaton futó későbbi lekérdezések rendesen betartják az időkorlátot. Ha agresszív első lekérdezési időtúllépéseket állítasz be egy csoportos munkaterhelésen, vedd figyelembe ezt a viselkedést, vagy kapcsold ki a MARS-t, MultipleActiveResultSets=false ha nincs rá szükséged. Lásd a MARS és a csoportosítás megjegyzését a Connection pooling részben.
Tartós PDO kapcsolatok nem támogatottak
PDO_SQLSRV elutasítja PDO::ATTR_PERSISTENT. A konstruktor dobásokra való beállítás:
SQLSTATE[IMSSP]: An unsupported attribute was designated on the PDO object.
Használd az ODBC kapcsolati poolinget a keresztkérések újrahasználatához. Ez az illesztőprogram natív mechanizmusa, mind a PDO_SQLSRV, mind az SQLSRV esetében működik, és CPTimeout esetén megszünteti a tétlen kapcsolatokat (ami a Microsoft Entra tokenfrissítés megfelelő működését is biztosítja).
Használja újra a kapcsolatot egy kérésen belül
Még pooling esetén is, ha új PDO vagy SQLSRV kapcsolatot nyitnak, ODBC út szükséges egy csoportos handle lekérésére és validálására. Kérvényenként egyszer nyiss kapcsolatot, és továbbítsd minden függvénynek, amelyre szüksége van.
Tip
Egy függőségi injekciós tartály vagy egy lusta kiegészítő elegendő. A lényeg, hogy kerüld new PDO(...) a kéréskezelő közepén.
Csak azt kérdezd meg, amire szükséged van
A hálózati körbejárások és az eredményhalmaz-materializáció uralják a lekérdezések késleltetését a legtöbb PHP munkaterhelésnél. A javítások ugyanazok, amelyek minden adatbázis-hozzáférési rétegre vonatkoznak.
Csak azokat az oszlopokat válaszd ki, amiket használsz
SELECT * minden oszlopot lehúz, beleértve a varchar(max) és varbinary(max) oszlopokat is, amelyek eltörpítik az valójában fogyasztott adatokat. Nevezd el az oszlopokat:
<?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");
Csak azokat a sorokat hozd meg, amire szükséged van
A szűrést küldje le az SQL Servernek. Soha ne tölts be egy teljes adatbázistáblát a PHP-be pusztán azért, hogy egy foreach ciklusban szűrj.
<?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);
Nagy eredményhalmazok lapozása
Ha egy listanézetet szeretnél, amely néhány száz sort mutat a millióból, ne add vissza az összes sort, és hagyd, hogy az ügyfél rendezze a dolgokat. Használj szerveroldali oldali lapozást a következőkkel 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álaszd ki a megfelelő lekérési módszert
- Használd a
fetch(PDO::FETCH_ASSOC)elemet egy ciklusban folyamatos iterációhoz, amikor nincs szükséged arra, hogy az összes sor egyszerre a memóriában legyen. - Használd
fetchAll(PDO::FETCH_ASSOC), amikor a hívónak valóban szüksége van az egész halmazra (például teljes JSON válasz megjelenítése). - Használd a(z)
fetchColumn()elemet, ha csak egyetlen skalár érdekel (egyCOUNT,SUMvagyMAX). - Használd a
PDO::FETCH_KEY_PAIRvagy aPDO::FETCH_UNIQUEelemet keresési szótárak létrehozásához második feldolgozási kör nélkül.
A numerikus behozási módok (PDO::FETCH_NUM) kissé gyorsabbak, mint az asszociatív behozási módok, mert kihagyják az oszlopnév leképezés felépítését. A tisztaságot részesítjük előnyben; Csak akkor váltson át, ha egy profiler jelentős fellépést jelöl.
A tárolt eljárásokban és kötegekben részesítse előnyben a(z) SET NOCOUNT ON elemet
Minden INSERT, UPDATE, és DELETE utasítás egy DONE_IN_PROC tokent ad vissza az érintett sorszámmal, amit a PHP általában eldob. A token nem ad hozzá egy újabb oda-vissza kört, de mindegyik így is bájtokat visz át a hálózaton, és némi illesztőprogram-oldali feldolgozást igényel. Egy többmondatos eljárásban vagy batchben, amely hívásonként több száz kijelentést futtat, a megtakarítások összegződnek. Kapcsold ki:
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;
Adatok hatékony beszúrása
Válaszd ki a megfelelő behelyezési módszert az alapján, hogy hány sort mozgaszol. A rossz választás akár százszor lassabb is lehet.
Kevesebb, mint körülbelül 100 sor: előkészített állítás egy hurokban
Kis adagok esetén hajtsunk végre egyetlen előkészített utasítást egy hurokban:
<?php
$stmt = $conn->prepare("INSERT INTO dbo.Products (Name, Price) VALUES (?, ?)");
foreach ($products as $p) {
$stmt->execute([$p["name"], $p["price"]]);
}
Foglaljuk a ciklust egy tranzakcióba, hogy az összes beszúrás egyetlen egységként véglegesedjen, és a naplót ne kelljen minden sor után kiüríteni:
<?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;
}
Több száz vagy millió sor: táblázatértékű paraméterek
A táblázatértékű paraméterek (TVP-k) az egész kötetet egy körúton elküldik az SQL Server-re, és hagyják, hogy az SQL Server egyetlen utasításként dolgozza fel a halmazt. Több száz sorból álló tételeknél a TVP-k általában sokkal gyorsabbak, mint egy előre állított ciklus, és lineárisan skálázódnak a sorszámmal.
Először hozz létre egy táblázattípust a szerveren:
CREATE TYPE dbo.ProductTableType AS TABLE (
Name NVARCHAR(100),
Price DECIMAL(10, 2)
);
PDO_SQLSRV a TVP-t asszociatív tömbként továbbítja, amelynek kulcsa a típusnév, és az értéke a sorhalmaz. Kötd meg a következőkkel 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();
Egy nem alapértelmezett séma esetén adjuk át a sémát a tömb következő elemeként: ["ProductTableType" => $rows, "Sales"]. Az SQLSRV eljárási szintaxisának és tárolt eljárás példáiért lásd: Táblázatértékű paraméterek használata.
Milliónyi sor: bcp vagy BULK INSERT
Igazán tömeges műveletekhez (adatraktár terhelések, kezdeti migrációk) használj bcp-t vagy BULK INSERT a PHP helyett. Írd le az adataidat egy definiált vagy natív formátumú fájlba, majd futtatd a bcp-t vagy BULK INSERT egy tervezett feladatból, ETL lépésből vagy admin scriptből.
Figyelmeztetés
Ha a PHP-ból a shell_exec() vagy a proc_open() használatával hívod meg a bcp-t, soha ne illessz be nem megbízható bemenetet a parancssorba. Használd a escapeshellarg() elemet minden argumentumnál, és a betöltést inkább a webes kérési útvonaltól függetlenül futtasd, ne a webes kérési útvonalon.
Csökkentsék a oda-vissza utakat
Minden hálózati oda-vissza út a PHP és az SQL Server között fix költséggel jár. Ha öt kimutatást egyetlen kötegben küldesz el, ezt a költséget csak egyszer fizeted meg, nem pedig ötször.
Kapcsolódó állítások egyesítése egyetlen tételben
Az együtt futó kapcsolódó műveletek esetén foglalja az utasításokat egy kötegbe, és dolgozza fel az összes eredményhalmazt:
<?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);
SQLSRV esetén használd sqlsrv_next_result az eredményhalmazok közötti előrehaladáshoz.
Engedélyezd a több aktív eredménykészletet, amikor szükséged van rá
A Multiple Active Result Set (MARS) lehetővé teszi, hogy egyetlen kapcsolat több aktív utasítást tartalmazzon. MARS nélkül nem lehet új lekérdezést küldeni olyan kapcsolaton, amelynek még mindig nyitott eredményhalmaza van. Mindkét illesztőprogram alapértelmezés szerint engedélyezi a MARS használatát. A kikapcsolásához állítsd a kapcsolati karakterláncban ezt: MultipleActiveResultSets=false. Lásd : Több aktív eredményhalmaz (MARS) letiltása.
A MARS kényelmes, de nem ingyenes. Minden aktív eredményhalmaz szerveroldali erőforrásokat fogyaszt. Lehetőleg dolgozzon fel teljesen egy eredményhalmazt, mielőtt egy másik feldolgozását megkezdi. Használd a MARS-t a valóban beágyazott kurzorminták blokkolásához.
Előkészített utasítások hangolása
Az előkészített utasítások megmentik a meghajtót az SQL újraparzálásától a szerveren, és lehetővé teszik, hogy biztonságosan megbízhatatlan bemenetet kötsd paraméterként.
A natív készítményeket részesítem előnyben
A PDO_SQLSRV két módban képes utasításokat előkészíteni.
A natív előkészített utasítások egyszer küldik el az SQL-szöveget a szervernek, majd minden végrehajtáskor újra felhasználják az értelmezett utasítást, és minden execute()alkalommal csak a paraméterértékeket küldik el.
Az emulált előkészületek az SQL szöveget az ügyfélben tartják, és újraépítenek egy teljes SQL stringet, amelynek paraméterei interpolálnak minden végrehajtáson.
Állítsd be úgy a(z) PDO::ATTR_EMULATE_PREPARES => false értéket, hogy az illesztőprogram natív előkészített utasításokat használjon. A natív előkészített utasítások lehetővé teszik, hogy az SQL Server gyorsítótárazza és újra felhasználja a lekérdezési tervet, valamint elkerülhetővé teszik az SQL-szöveg minden egyes végrehajtáskori újbóli elemzését.
<?php
$conn = new PDO($dsn, null, null, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
]);
Felhasználd újra a felkészített nyilatkozatokat
Egyszer készülj, sokat végezz ki. Minden prepare() hívás egy ODBC handle allokációt és szerveroldali parse-t igényel. Hot loop esetén tartsuk életben az $stmt objektumot, és hívjuk execute() a hurkon belül:
<?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"]]);
}
Vigyázz a TOP (?) és IN (?, ?, ...)
TOPegy paraméterjelölő SELECT TOP (?) ...körül zárójeleket igényel, így az SQL Server paraméterként képes a sorszámot parzírozni.
IN (?, ?, ?, ?) rögzített helykitöltő számot igényel az előkészítési időben. Változó IN listaméretek esetén a helyőrzőkarakterláncot vagy egy ellenőrzött egész darabszámból kell felépíteni, vagy a listát táblázatértékű paraméterként kell átadni.
Figyelmeztetés
Soha ne interpoláld a nyers felhasználói bemenetet az SQL szövegbe (beleértve a helyjelző számot is). A helyőrző karakterlánc létrehozása előtt alakítsd át a count értékét a(z) (int) használatával, és a tényleges értékeket mindig paraméterként add át a(z) execute() használatával.
A kurzorok és memória kezelése
Az alapértelmezett kurzor típusa, PDO::CURSOR_FWDONLYegy csak előre használható tűzcső. Egyenként továbbítja a sorokat a PHP-be, és nem pufferel, így egy nagy eredményhalmazt sor-buffer memória korlátozza a teljes sorszám helyett. Általában ezt akarod.
Csak akkor használd a pufferelt kurzorokat, ha visszafelé kell mozdulnod vagy sorokat számolnod kell
PDO::SQLSRV_CURSOR_BUFFERED (kliens oldali pufferelt statikus kurzor) előre lehozza az egész eredményhalmazt a PHP memóriába. Ez a megközelítés lehetővé teszi, hogy meghívd a(z) rowCount() elemet, visszafelé kereshetsz, és újra felhasználhasd az utasítást. Alapértelmezés szerint a puffer felső korlátja PDO::SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZE segítségével 10 240 KB (10 MB), és az a lekérdezés, amelynek eredményhalmaza meghaladja ezt a korlátot, a PHP-memória túlcsordítása helyett false értékkel tér vissza. A korlátot megemelheted a PHP memóriakorlátjáig, de ezzel a false visszatérést egy valódi Allowed memory size exhausted végzetes hibára cseréled, ha egy lekérdezés meghaladja az új korlátot. Finomhangoljon tudatosan.
Lásd a kurzor típusokat (PDO_SQLSRV).
A szerveroldali görgethető kurzorok (PDO::SQLSRV_CURSOR_STATIC, PDO::SQLSRV_CURSOR_DYNAMIC, PDO::SQLSRV_CURSOR_KEYSET) a szerveren pufferelnek a kliens helyett, így nem fogyasztanak PHP memóriát. Azonban a kurzor teljes élettartama alatt szerveroldali erőforrásokat kötnek le, és soronként lassabbak, mint az egyirányú kurzorok.
A streamelési olvasásokhoz az alapértelmezett, csak előre irányuló módot használd. Használj kliensoldali pufferelést kis méretű eredményhalmazok esetén, amikor rowCount() vagy visszafelé görgetésre van szükség. Kerüld a szerveroldali görgethető kurzorokat, hacsak nem csinálsz valami konkrétat.
<?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();
A teljes bontásért lásd: Cursor types (PDO_SQLSRV) és Cursor types (SQLSRV).
Nagyméretű bináris és karakteres értékek folyamatos átvitele
Varbinary(max), varchar(max), nvarchar(max), xml és más nagy típusok esetén használjunk PHP folyamokat ahelyett, hogy az egész értéket memóriában materializálnád:
<?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);
Nagyméretű értékek beszúrásához vagy frissítéséhez az SQLSRV-ben a(z) sqlsrv_execute() után a SendStreamParamsAtExec=false használatával darabokban küldje el az adatfolyamot. Részletekért lásd: Adatküldés adatfolyamként.
Megfelelő időtúllépések beállítása
Az időkorlátok legalább annyira teljesítménybeállítások, mint megbízhatósági beállítások. A hosszan futó lekérdezések lefoglalják a kapcsolatkészlet kapcsolatait, és elvonják az erőforrásokat a többi kéréstől.
Kijelentés időtúllépése
Állítson be utasításonkénti időkorlátot, hogy egy beragadt lekérdezés ne tartsa lefoglalva korlátlan ideig a kapcsolatkészlet egyik kapcsolatát. PDO_SQLSRV számára:
<?php
$stmt = $conn->prepare("SELECT ... FROM dbo.HugeTable ...");
$stmt->setAttribute(PDO::SQLSRV_ATTR_QUERY_TIMEOUT, 30); // seconds
$stmt->execute();
SQLSRV esetén add át a "QueryTimeout" => 30 elemet a sqlsrv_query vagy a sqlsrv_prepare függvénynek átadott opciótömbben.
Állíts be olyan értéket, ami megfelel a munkaterhelésednek. Egy szinkron webes kéréshez általában 15-30 másodperc szükséges. Egy háttérben lévő részmunka esetén több perc is ésszerű lehet. Soha ne állítsa az időtúllépési értéket nullára (korlátlanra) webes kérés esetén.
Bejelentkezési időtúllépés
LoginTimeouta kapcsolati karakterlánc szabályozza, mennyi ideig vár a meghajtó a kapcsolat létrejöttéhez. Állíts be explicit értéket, amikor Azure SQL Database-hez vagy Azure SQL Managed Instance-hoz csatlakozol, hogy a hidegindítások és a failover-group failover-ek ne akasztják le a klienst határozatlan időre. A 30 és 90 másodperc közötti értékek a legtöbb felhőalapú munkaterhelésnél jól működnek. A LoginTimeout és a ConnectRetryCount * ConnectRetryInterval egymáshoz viszonyított méretezésével, valamint az ebből eredő hibamódokkal kapcsolatos részletekért lásd a Kapcsolati időkorlát című részt. Az opciók hivatkozásához lásd: Csatlakozási opciók.
Irányítsa az csak olvasható munkaterheléseket egy replikára
Adatbázison végrehajtott csak olvasási lekérdezésekhez egy Always On rendelkezésre állási csoportban, Azure SQL Managed Instance-ben, illetve olvasási horizontális felskálázással vagy georeplikával rendelkező Azure SQL Database-ben add hozzá a ApplicationIntent=ReadOnly elemet a kapcsolati karakterlánchoz:
<?php
$dsn = "sqlsrv:Server=<listener>;Database=<database>;" .
"Encrypt=true;ApplicationIntent=ReadOnly";
Az csak olvasható útválasztás a kapcsolatot egy szinkronizált másodlagos replikához küldi, leterheli a munkát az elsődleges rendszerről. A MultiSubnetFailover=true használatával érhető el a leggyorsabb csatlakozás a több alhálózatos rendelkezésre állási csoport figyelőihez.
A szerver teljesítményének megfigyelése
Az ügyféloldali időzítés csak azt mutatja, mennyi ideig tartott egy lekérdezés végétől végéig. Ahhoz, hogy megtudjad, miért volt lassú, használd az SQL Server beépített diagnosztikaát.
Kérdéstár
A Query Store rögzíti a végrehajtási terveket, futási idejű statisztikákat és várakozási statisztikákat minden lekérdezéshez az adatbázison. Ez alapértelmezettségben engedélyezett az Azure SQL Database-en, Azure SQL Managed Instance-on, valamint az SQL adatbázison a Fabric-ben. Az SQL Serverben adatbázisonként engedélyezd:
ALTER DATABASE <database_name> SET QUERY_STORE = ON;
Ezután használd az SQL Server Management Studio Query Store jelentéseit, hogy megtaláld a leglassabb és leggyakrabban lefuttatott lekérdezéseidet. Lásd: Teljesítmény monitorozása a Query Store-ban.
Azure SQL Query Performance Insight
Azure SQL Database esetén az Azure portál Query Performance Insight automatikusan megjeleníti a leginkább erőforrás-igénylő lekérdezéseket konfiguráció nélkül. További információ: Az Azure SQL Database lekérdezési terheléselemzője.
SET STATISTICS egyszeri vizsgálathoz
Egyetlen lekérdezés esetén, amit profilozni szeretnél, futtasd be az SQL Server Management Studio-ban, statisztikák bekapcsolva:
SET STATISTICS TIME ON;
SET STATISTICS IO ON;
-- your query here
A magas logikai olvasások szinte mindig hiányzó vagy használhatatlan indexet jelentenek. Magas CPU-idő alacsony logikai olvasással általában rossz tervet jelent (paraméter szimatolása, implicit átalakítás, amely megakadályozza az index használatát, vagy skaláris függvény, amely megakadályozza a párhuzamosságot).
Extended Events az illesztőprogram-szintű nyomkövetéshez
Ahhoz, hogy pontosan lássuk, mit küld az illesztőprogram az SQL Servernek (beleértve az általa behelyettesített tényleges paraméterértékeket is), rögzítsünk egy Extended Events munkamenetet a rpc_completed és sql_batch_completed események használatával.
Teljesítmény-ellenőrzőlista
Ezt az ellenőrzőlistát használd telepítés előtti áttekintésként bármely olyan PHP alkalmazásról, amely csatlakozik az SQL Server-hez:
| Area | Ellenőriz | Reference |
|---|---|---|
| Connection | A platformon a kapcsolatpooling engedélyezve van és konfigurálva van. | Kapcsolatok hatékony kezelése |
| Connection | Az alkalmazás újrahasználja a kapcsolatokat egy kérésen belül, és nem nyit meg lekérdezésenként kapcsolatokat | A kapcsolat újrafelhasználása egy kérésen belül |
| Connection |
LoginTimeout lefedi a hidegindításokat és a feladatátvételt az Azure SQL esetében |
Bejelentkezési időkorlát |
| Query | A lekérdezések csak a szükséges oszlopokat választják ki, nem SELECT * |
Csak azokat az oszlopokat válaszd ki, amiket használsz |
| Query | A szűrés SQL-ben történik, nem PHP-ben array_filter |
Csak azokat a sorokat hozd meg, amire szükséged van |
| Query | Nagy eredményhalmazok a következőképpen vannak oldalozva, OFFSET ... FETCH |
Nagy eredményhalmazok oldalakra bontása |
| Query | Tárolt eljárások halmaza SET NOCOUNT ON |
Előnyben részesítem SET NOCOUNT ON |
| Beillesztés | A tömeges beillesztések táblázatértékű paramétereket használnak, nem soronkénti hurkokat | Adatok hatékony beszúrása |
| Kimutatások |
PDO::ATTR_EMULATE_PREPARES beállítva van false |
A natív készítményeket részesítem előnyben |
| Kimutatások | Az alkalmazás újrahasználja az előkészített utasításokat az elvégzések során | Felhasználd újra a felkészített nyilatkozatokat |
| Cursors | Az alkalmazás az alapértelmezett csak előre használható kurzort használja, hacsak nem szükséges pufferezés | A kurzorok és memória kezelése |
| Memory | A nagy bináris és karakteres értékek streamként kerülnek feldolgozásra, nem teljes egészükben a memóriába kerülnek. | Nagy bináris és karakteres értékek streamelése |
| Időtúllépések | Az utasítási időkorlát az összes felhasználói lekérdezéshez be van állítva | Jelentés időkorlát |
| Útválasztás | Csak olvasható munkaterhelések beállítása ApplicationIntent=ReadOnly, ahol replika létezik |
Útvonal csak olvasható munkaterhelések |
| Observability | A Query Store engedélyezve van, és rendszeresen felülvizsgálják | Lekérdezéstár |
Kapcsolódó tartalom
- Kapcsolatcsoportosítás (Microsoft Drivers for PHP for SQL Server)
- Kapcsolati beállítások
- Kurzortípusok (PDO_SQLSRV illesztő)
- Kurzortípusok (SQLSRV-illesztő)
- Táblázatértékű paraméterek (PHP) használata
- A Microsoft SQL Serverhez készült PHP-illesztőprogramok hibaelhárítása
- A teljesítmény figyelése a Query Store használatával