Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Bu makale, SQL Server, Azure SQL Veritabanı, Azure SQL Yönetilen Örneği, Azure Synapse Analytics ve Microsoft Fabric'te SQL veritabanı ile hızlı PHP kodu nasıl yazılacağını ele alır. Rehberlik, aynı Microsoft ODBC Sürücüsünü SQL Server için saran hem SQLSRV hem de PDO_SQLSRV için geçerlidir.
En yüksek etkili değişikliklerle başlayın
Sadece üç değişiklik yapabiliyorsanız, şu değişiklikleri yapın:
- Bağlantı havuzunu etkinleştirin. SQL Server'a yeni bir TLS bağlantısı kurmak, ağ yolu ve TLS müzakere sürecine bağlı olarak onlarca ila yüzlerce milisaniye sürer. Havuzlu bağlantıları yeniden kullanmak, istek başına bu maliyeti ortadan kaldırır. Bağlantıları verimli yönetin bkz.
- Sadece ihtiyacınız olan sütunları ve satırları getirin.
SELECT *ve sınırsız sorgular, yavaş uç noktaların en yaygın nedenleridir. Sadece ihtiyacınız olanı sorgulayın. - Toplu eklemeler için tablo değerli parametreler kullanın. Yüzlerce satır veya daha fazla için, tablo değerli parametreler (TVP) genellikle satır
INSERTsatır ifadelerden çok daha hızlıdır ve satır sayısıyla doğrusal ölçeklenir. Verileri verimli şekilde ekle sayfasına bakınız.
Bağlantıları verimli yönetin
Bağlantı kurmak, sürücünün yaptığı en pahalı operasyondur. Neredeyse her PHP performans incelemesi bağlantı yönetimi düzeltmesiyle sonuçlanır.
Bağlantı havuzunu etkinleştirme
Havuzlama, PHP istekleri arasında ODBC bağlantılarını tekrar kullanır, istek sonunda onları sökülmek yerine. Bağlantı nesnesi scriptiniz bittiğinde atılır, ancak altta yatan ODBC handle ODBC sürücü yöneticisinin havuzunda canlı kalır ve aynı bağlantı dizesi'i isteyen sonraki istekte tekrar kullanılır.
Windows: Bağlantı havuzu varsayılan olarak açık. Doğrulamak için, bu ConnectionPooling seçeneği DSN'inizden çıkarın. Hata ayıklama için havuzlama devre dışı bırakmak için ConnectionPooling=0.
Linux ve macOS: Bu platformlarda bağlantı havuzu seçeneği DSN seçeneği değildir. Sürücü yöneticisinde Pooling=Yes[ODBC] , bölümünde odbcinst.iniayarla etkinleştirin ve sürücünün kıtasının altına pozitif CPTimeout bir konum ayarlayın. Örneğin:
[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
Gerçek kütüphane yolunu veya odbcinst -q -d -n "ODBC Driver 18 for SQL Server"ls /opt/microsoft/msodbcsql18/lib64/ile bulun. Dosya adı, kurulu ODBC sürücü sürümünü gömüyor ve her sürümle değişir.
CPTimeout (saniyeler içinde) boşta bağlantıların havuzda ne kadar kalacağını kontrol eder, sonra kapanır. Çoğu isteği havuzlu bir bağlantı bulacak kadar yüksek, ama başarısız bir sunucuya gelen eski bağlantıların makul bir şekilde emekliye çıkması için yeterince düşük ayarlayın. 60 ila 300 saniye çoğu web iş yükü için iyi çalışıyor.
Detaylar için bkz. Bağlantı havuzlama.
İlk sorgu maliyetini anlayın
Birden çok Etkin Sonuç Kümesi (MARS) varsayılan olarak etkindir. MARS ve bağlantı havuzu aktifse, sürücü ilk sorguda havuzlu bağlantıyı sıfırlar ve bu sıfırlama, o ilk sorgu için ayarladığınız sorgu zaman aşımını görmezden gelir. Aynı bağlantıdaki sonraki sorgularda zaman aşımına normal şekilde saygı gösteriliyor. Havuzlu bir iş yükünde agresif ilk sorgu zaman aşımları belirlerseniz, bu davranışı hesaba katabilir veya ihtiyacınız yoksa MARS'ı MultipleActiveResultSets=false devre dışı bırakın.
Bağlantı havuzlama bölümünde MARS ve havuzlama notuna bakınız.
Kalıcı PDO bağlantıları desteklenmiyor
PDO_SQLSRV reddediyor PDO::ATTR_PERSISTENT. Yapıcı atışlara koyarken:
SQLSTATE[IMSSP]: An unsupported attribute was designated on the PDO object.
Çapraz istek yeniden kullanımı için ODBC bağlantı havuzunu kullanın. Bu, sürücünün yerel mekanizmasıdır, hem PDO_SQLSRV hem de SQLSRV için çalışır ve boşta bağlantıları CPTimeout emekte bırakır (bu da token yenilemesini dürüst Microsoft Entra tutar).
Bağlantıyı bir istek içinde yeniden kullanın
Havuzlama sırasında bile, yeni bir PDO veya SQLSRV bağlantısı açmak, havuzlu bir handle almak ve doğrulamak için ODBC gidiş-dönüş süreci gerektirir. Her istek için bir kez bağlantı açın ve ihtiyacı olan her fonksiyona ilet.
Tip
Bir bağımlılık enjeksiyonu kapı veya tembel bir aksesuar yeterlidir. Amaç, bir istek yöneticisinin ortasında olmaktan kaçınmaktır new PDO(...) .
Sadece ihtiyacınız olanı sorgulayın
Ağ dönüş yolculukları ve sonuç seti gerçekleştirme çoğu PHP iş yükünde sorgu gecikmesini kontrol eder. Düzeltmeler, her veritabanı erişim katmanına uygulanan aynı düzeltmelerdir.
Sadece kullandığınız sütunları seçin
SELECT *
Varchar(max) ve varbinary(max) sütunları dahil olmak üzere her sütunu çeker, bunlar aslında tükettiğiniz veriyi gölgede bırakır. Sütunlara isimler verin:
<?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");
Sadece ihtiyacın olan sıraları getir
Filtrelemeyi SQL Server'a it. Asla PHP'ye tam bir tablo getirme, döngü içinde filtrelemek foreach için.
<?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);
Büyük sonuç kümelerini sayfalandır
Milyonlarca satırdan birkaç yüz satırı gösteren bir liste görünümü için, tüm satırları geri göndermeyin ve müşterinin çözmesine izin verin. Sunucu tarafı sayfalamayı şu OFFSET ... FETCHile kullanın:
<?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);
}
Doğru getirme yöntemini seçin
- Tüm satırları aynı anda hafızada kullanmak zorunda olmadığınızda akış iterasyonu için döngü içinde
fetch(PDO::FETCH_ASSOC)kullanın. -
fetchAll(PDO::FETCH_ASSOC)Arayan gerçekten tüm seti kullanmak istediğinde (örneğin, tam bir JSON yanıtı oluşturmak) kullanın. - Sadece tek bir skaler (a
COUNT,SUM, veyaMAX) önemsediğinde kullanınfetchColumn(). - İkinci bir geçiş olmadan sözlükleri arama sözlüğü oluşturmak için kullanabilirsin
PDO::FETCH_KEY_PAIRPDO::FETCH_UNIQUE.
Sayısal getirme modları (PDO::FETCH_NUM) ilişkilendirilebilir getirme modlarından biraz daha hızlıdır çünkü sütun-adı haritasını oluşturmayı atlarlar. Açıklığı tercih eder; Sadece bir profiler overhead'i önemli olarak işaretlediğinde anahtar değiştirir.
Depolanmış prosedürler ve partilerde tercih SET NOCOUNT ON edilir
Her INSERT, UPDATE, ve DELETE ifadesi etkilenen sıra sayısına sahip bir DONE_IN_PROC token döndürür, PHP genellikle bu tokenı atar. Token gidiş-dönüş eklemez ama her biri kablo üzerinde baytlar ve az miktarda sürücü işi gerektiriyor. Her çağrıda yüzlerce ifade çalıştıran çoklu ifade prosedürü veya toplu bir grupta, tasarruflar biriktirilir. Kapatın:
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;
Veriyi verimli şekilde ekle
Kaç sıra hareket ettirdiğinize göre doğru yerleştirme yöntemini seçin. Yanlış seçim 100 kat daha yavaş olabilir.
Yaklaşık 100 satırdan az: bir döngüde hazırlanmış ifade
Küçük partiler için, bir döngüde tek bir hazırlanmış ifade çalıştırın:
<?php
$stmt = $conn->prepare("INSERT INTO dbo.Products (Name, Price) VALUES (?, ?)");
foreach ($products as $p) {
$stmt->execute([$p["name"], $p["price"]]);
}
Döngüyü bir işlemde sararak tüm ekleyiciler tek bir birim olarak commit etsin ve log her satırdan sonra kayda geçmesin:
<?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;
}
Yüzlerce hatta milyonlarca satır: tablo değerli parametreler
Tablo değerli parametreler (TVP'ler) tüm grubu tek bir dönüşte SQL Server'a gönderir ve SQL Server'ın kümeyi tek bir ifade olarak işlemesini sağlar. Yüzlerce veya daha fazla satır içeren partiler için, TVP'ler genellikle hazırlanmış bir ifade döngüsünden çok daha hızlıdır ve satır sayısıyla doğrusal ölçeklenir.
İlk olarak, sunucuda bir tablo türü oluşturun:
CREATE TYPE dbo.ProductTableType AS TABLE (
Name NVARCHAR(100),
Price DECIMAL(10, 2)
);
PDO_SQLSRV, TVP'yi anahtarı tür adı ve değeri satır kümesi olan ilişkili bir dizi olarak geçirir. Bağlayın 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();
Varsayılan olmayan bir şema için, dizinin bir sonraki elemanı olarak şemayı iletin: ["ProductTableType" => $rows, "Sales"]. SQLSRV prosedürel sözdizimi ve saklanan prosedür örnekleri için bkz. Tablo değerli parametreler kullanın.
Milyonlarca satır: bcp veya BULK INSERT
Gerçekten toplu işlemler için (veri deposu yükleri, ilk göçler) bcp veya BULK INSERT PHP yerine kullanın. Verilerinizi sınırlandırılmış veya yerel formatlı bir dosyaya yazın, ardından bcp'yi veya BULK INSERT planlanmış bir işten, ETL adımından veya yönetici betikten çalıştırın.
Caution
PHP'den shell_exec() bcp'ye para harcıyorsanız veya proc_open(), asla güvenilmeyecek girdileri komut satırına interpolasyon yapmayın. Her argümanda kullanın escapeshellarg() ve yükü web isteği yolunda çalıştırmak yerine bant dışı çalıştırmayı tercih edersiniz.
Gidiş-dönüş sayısını azaltın
PHP ile SQL Server arasındaki her ağ gidiş-dönüş yolculuğunun sabit bir maliyeti vardır. Beş ifade tek bir grup olarak gönderdiğinizde, bu maliyeti beş kat yerine bir kez ödersiniz.
İlgili ifadeleri tek bir toplu olarak birleştirin
İlgili ve birlikte çalışan çalışmalar için, ifadeleri tek bir grupta toplayıp tüm sonuç kümesini tüketin:
<?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 için, sonuç kümeleri arasında ilerlemek için kullanılır sqlsrv_next_result .
İhtiyacınız olduğunda birden fazla aktif sonuç setini etkinleştirin
Çoklu Aktif Sonuç Setleri (MARS), tek bir bağlantının birden fazla aktif ifadeye sahip olmasını sağlar. MARS olmadan, hala açık sonuç kümesi olan bir bağlantıda yeni bir sorgu gönderemezsiniz. Her iki sürücü de varsayılan olarak MARS'ı etkinleştiriyor. Kapatmak için MultipleActiveResultSets=false bağlantı dizesi'inizi ayarlayın.
Bkz. Birden Fazla Aktif Sonuç Seti (MARS) Devre Dışı Bırak.
MARS kullanışlıdır ama ücretsiz değildir. Her aktif sonuç kümesi, sunucu tarafı kaynakları tüketir. Bir sonuç setini tam tüketmeyi tercih edin, sonra bir başka bir tane başlatın. Gerçekten iç içe imleç desenlerini açmak için MARS kullanın.
Tune, hazırladığı açıklamalar
Hazırlanmış ifadeler, sürücünün sunucuda SQL'i yeniden ayrıştırmasını engeller ve güvenilmez girdileri parametre olarak güvenle bağlamanıza olanak tanır.
Yerel hazırlıkları tercih edin
PDO_SQLSRV iki modda ifade hazırlayabilir.
Yerel olarak SQL metnini sunucuya bir kez gönderir ve her çalıştırma için ayrıştırılmış ifadeyi tekrar kullanır, yalnızca her execute()bir parametre değerini gönderir.
Emülle edilen hazırlıklar, SQL metnini istemcide tutar ve her çalıştırmada parametrelerle tam bir SQL dizisi yeniden oluşturur.
Sürücünün yerel hazırlıkları kullanmasını sağla PDO::ATTR_EMULATE_PREPARES => false . Yerel hazırlıklar, SQL Server'ın önbellek alıp sorgu planını yeniden kullanmasına izin verir ve her yürütmede SQL metnini yeniden ayrıştırmaktan kaçınır.
<?php
$conn = new PDO($dsn, null, null, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
]);
Hazırlanmış ifadeleri yeniden kullanın
Bir kez hazırlan, birçok kişiyi idam et. Her prepare() çağrı bir ODBC handle tahsisi ve sunucu tarafı ayrıştırma gerektirir. Sıcak döngüde, nesneyi $stmt canlı tutun ve döngü içinde çağırın execute() :
<?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"]]);
}
Dikkat edin TOP (?) ve IN (?, ?, ...)
TOPparametre işaretçisi etrafında parantez gerektirir, SELECT TOP (?) ...böylece SQL Server satır sayısını parametre olarak ayrıştırabilir.
IN (?, ?, ?, ?) Hazırlık zamanında sabit bir yer tutucu sayı gerektirir. Dinamik IN liste boyutları için, ya doğrulanmış bir tam sayı sayından yer tutucu diziyi oluşturun ya da listeyi tablo değerli bir parametre olarak aktarın.
Caution
Ham kullanıcı girdisini SQL metnine (yer tutucu sayısı dahil) asla interpolasyon yapmayın. Place-holder dizisi oluşturmadan önce sayını ile (int) yapın ve gerçek değerleri her zaman parametre olarak geçirin execute() .
İmleci ve belleği yönetin
Varsayılan imleç türü PDO::CURSOR_FWDONLY, sadece ileri sinfi bir yangın hortumudur. Satırları PHP'ye teker teker akış yapar ve tamponlamaz, bu yüzden büyük bir sonuç kümesi, toplam satır sayısı yerine satır-buffer belleği ile sınırlanır. Genellikle istediğin şey bu.
Tamponlu imleçleri sadece geriye doğru hareket etmeniz veya satır saymanız gerektiğinde kullanın
PDO::SQLSRV_CURSOR_BUFFERED (istemci tarafı tamponlu statik imleci) tüm sonuç setini önceden PHP belleğine getirir. Bu yaklaşım, geri arama rowCount()ve ifadeyi tekrar kullanma imkanı verir. Varsayılan olarak, buffer 10.240 KB (10 MB) ile sınırlandırılır ve PDO::SQLSRV_ATTR_CLIENT_BUFFER_MAX_KB_SIZEcap kümesini aşan sorgu, PHP belleği taşmak yerine geri döner false . PHP bellek sınırına sınırı artırabilirsiniz, ancak bunu yaparsanız, bir sorgu yeni sınırı aştığında geri dönüşü gerçek Allowed memory size exhausted ölümcül bir hata ile değiştirirsinizfalse. Kasıtlı olarak akort edin.
Bkz. İmleç tipleri (PDO_SQLSRV).
Sunucu tarafında kaydırılabilir imleçler (PDO::SQLSRV_CURSOR_STATIC, PDO::SQLSRV_CURSOR_DYNAMIC, PDO::SQLSRV_CURSOR_KEYSET) istemci yerine sunucuda buffer yapar, böylece PHP bellek tüketmezler. Ancak, imleç süresi boyunca sunucu tarafı kaynaklarını tutar ve sadece ileri yönlendirmeye göre satır başına daha yavaştır.
Akış okumaları için varsayılan ileriye doğru sistemi kullanın. Küçük sonuç setleri için tampon tarafı kullanın veya geriye kaydırma yapın.rowCount() Belirli bir şey yapmıyorsanız, sunucu tarafında kaydırılabilir imleçlerden kaçının.
<?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();
Tam bir açıklama için bkz. Cursor types (PDO_SQLSRV) ve Cursor types (SQLSRV).
Büyük ikili ve karakter değerlerini akış
Varbinary(max), varchar(max), nvarchar(max), xml ve diğer büyük türler için, tüm değeri bellekte maddileştirmek yerine PHP akışları kullanın:
<?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);
Büyük değerlerle ekleme veya güncelleme için, SendStreamParamsAtExec=false SQLSRV'de akış verisini parça halinde göndermek sqlsrv_execute()için kullanın. Detaylar için bkz. Veri akışı olarak gönder.
Uygun zaman aşımlarını ayarlama
Zaman aşımları da güvenilirlik ayarları kadar performans ayarlarıdır. Uzun süreli sorular havuz bağlantılarını tutar ve diğer talepleri boş bırakır.
Deyim zaman aşımı
Bir hesap başına zaman sınırı belirleyin ki bir soru bir havuz bağlantısını sonsuza kadar tutmasın. PDO_SQLSRV için:
<?php
$stmt = $conn->prepare("SELECT ... FROM dbo.HugeTable ...");
$stmt->setAttribute(PDO::SQLSRV_ATTR_QUERY_TIMEOUT, 30); // seconds
$stmt->execute();
SQLSRV için, seçenekler dizisini veya sqlsrv_querysqlsrv_prepare'ye iletin"QueryTimeout" => 30.
İş yükünüze uygun bir değer belirleyin. Senkron web isteği için genellikle 15 ila 30 saniye olur. Arka plan partisi işi için birkaç dakika makul olabilir. Web isteğinde zaman aşımını sıfıra (sınırsız) asla ayarlamayın.
Oturum açma zaman aşımı
LoginTimeoutbağlantı dizesi'te sürücünün bağlantı kurmak için ne kadar beklediğini kontrol eder. Azure SQL Veritabanı veya Azure SQL Yönetilen Örneği'a bağlanırken açık bir değer belirleyin ki soğuk başlatmalar ve failover-grup failover'ları istemciyi süresiz olarak kapatmasın. 30 ila 90 saniye arasındaki değerler çoğu bulut iş yükü için iyi çalışır. Karşılaştırma LoginTimeoutConnectRetryCount * ConnectRetryInterval boyutları ve bunun sonucunda oluşan arıza modları hakkında detaylar için Bağlantı zaman aşımına bakınız. Seçenek referansı için Bağlantı seçenekleri sayfasına bakınız.
Yalnızca okunan iş yüklerini bir replikaya yönlendirme
Always On kullanılabilirlik grubundaki veritabanına yönelik yalnızca okunabilir sorgular için, Azure SQL Yönetilen Örneği veya okuma ölçeklendirme veya geo-replika ile Azure SQL Veritabanı için bağlantı dizesi'inize ekleyinApplicationIntent=ReadOnly:
<?php
$dsn = "sqlsrv:Server=<listener>;Database=<database>;" .
"Encrypt=true;ApplicationIntent=ReadOnly";
Yalnızca okunan yönlendirme, bağlantıyı senkronize ikincil bir replikaya gönderir ve birincil sistemden işleri boşaltır. Çoklu alt ağ erişilebilirlik grubu dinleyicilerine en hızlı bağlantı için birleştirin MultiSubnetFailover=true .
Sunucudan performansı gözlemleyin
İstemci tarafı zamanlama, sadece bir sorgunun uçtan uca ne kadar sürdüğünü gösterir. Neden yavaş olduğunu öğrenmek için SQL Server'ın yerleşik tanı sistemini kullanın.
Sorgu Mağazası
Query Store, veritabanındaki her sorgu için yürütme planlarını, çalışma zamanı istatistiklerini ve bekleme istatistiklerini yakalar. Azure SQL Veritabanı, Azure SQL Yönetilen Örneği ve Fabric'teki SQL veritabanında varsayılan olarak etkinleştirilmiştir. SQL Server'da, veritabanı başına etkinleştirin:
ALTER DATABASE <database_name> SET QUERY_STORE = ON;
Sonra SQL Server Management Studio'nun Query Store raporlarını kullanarak en yavaş ve en sık yapılan sorgularınızı bulabilirsiniz. Bkz. Performansı Query Store ile İzle.
Azure SQL Query Performance Insight
Azure SQL Veritabanı için, Azure portalının Query Performance Insight (Query Performance Database, herhangi bir yapılandırma olmadan en çok kaynak tüketen sorguları otomatik olarak gösterir. Daha fazla bilgi için Azure SQL Veritabanı için Sorgu Performansı İçgörüleri’ni inceleyin.
SET STATISTICS Tek seferlik soruşturma için
Profil vermek istediğiniz tek bir sorgu için, istatistikler açık şekilde SQL Server Management Studio'da çalıştırın:
SET STATISTICS TIME ON;
SET STATISTICS IO ON;
-- your query here
Yüksek mantıklı okumalar neredeyse her zaman eksik veya kullanılamaz bir indeks anlamına gelir. Yüksek CPU süresi ve düşük mantıksal okumalar genellikle kötü bir plan anlamına gelir (parametre koklama, indeks kullanımını engelleyen örtük dönüşüm veya paralelliği engelleyen skaler fonksiyon).
Sürücü düzeyinde takip için Genişletilmiş Etkinlikler
Sürücünün SQL Server'a tam olarak ne gönderdiğini (interpolasyon yaptığı gerçek parametre değerleri dahil) görmek için, ve sql_batch_completed olaylarını kullanarak rpc_completedGenişletilmiş Olaylar oturumunu yakalayın.
Performans denetim listesi
Bu kontrol listesini, SQL Server'a bağlanan herhangi bir PHP uygulamasının dağıtım öncesi incelemesi olarak kullanın:
| Alan | İşaretli | Reference |
|---|---|---|
| Connection | Platform için bağlantı havuzu etkinleştirilmiş ve yapılandırılmıştır | Bağlantıları verimli yönetin |
| Connection | Uygulama, bir istek içindeki bağlantıları tekrar kullanır ve her sorgu başına bağlantıları açmaz | Bağlantıyı bir istek içinde yeniden kullanın |
| Connection |
LoginTimeoutAzure SQL için soğuk başlatma ve failover kaplar |
Giriş süresi |
| Query | Sorgular sadece gerekli sütunları seçer, hayır SELECT * |
Sadece kullandığınız sütunları seçin |
| Query | Filtreleme SQL'de gerçekleşir, PHP'de değil array_filter |
Sadece ihtiyacın olan sıraları getir |
| Query | Büyük sonuç kümeleri şu şekilde sayfalanır OFFSET ... FETCH |
Büyük sonuç kümelerini sayfalayın |
| Query | Saklanan prosedürler kümesi SET NOCOUNT ON |
Tercihe SET NOCOUNT ON |
| Eklemeler | Toplu eklemeler, satır başına döngüler değil, tablo değerli parametreler kullanır | Veriyi verimli şekilde ekle |
| Statements |
PDO::ATTR_EMULATE_PREPARES
false olarak ayarlanır |
Yerel hazırlıkları tercih edin |
| Statements | Uygulama, hazırlanmış ifadeleri tüm işlemler arasında yeniden kullanır | Hazırlanmış ifadeleri yeniden kullanın |
| Cursors | Uygulama, buffer gerekmedikçe varsayılan ileri imleci kullanır | İmleci ve belleği yönetin |
| Memory | Büyük ikili ve karakter değerleri akış yoluyla yapılır, maddileştirilmez | Büyük ikili ve karakter değerlerini akış |
| Zaman aşımları | Kullanıcı tarafından yönlendirilen tüm sorgularda ifade zamanlaması ayarlanır | Statement mola |
| Routing | Replikanın bulunduğu yalnızca okunabilir iş yükleri seti ApplicationIntent=ReadOnly |
Rota yalnızca okunabilir iş yükleri |
| Observability | Query Store etkinleştirilmiş ve düzenli olarak inceleniyor | Query Store |