Rozwiązuj problemy ze sterownikami Microsoft dla PHP dla SQL Server

Pobieranie sterownika PHP

Zdiagnozuj i rozwiązuj typowe problemy, gdy używasz sterowników Microsoft for PHP for SQL Server, aby połączyć się z SQL Server, Azure SQL Database, Azure SQL Managed Instance oraz bazą danych SQL Microsoft Fabric.

Ogólne wzorce obsługi błędów i ostrzeżeń można znaleźć w sekcji Obsługa błędów i ostrzeżeń. Aby uzyskać diagnostyczne przechwytywanie po stronie kierowcy, zobacz Aktywność rejestrowania.

Problemy z instalacją

Rozszerzenie nieładowane

Objawy:

  • phpinfo() Nie zawiera sekcji A OR (Sekcji sqlsrv OR pdo_sqlsrv NE).
  • PDOException: could not find driver przy konstrukcji a PDO z DSN sqlsrv: .
  • Fatal error: Uncaught Error: Call to undefined function sqlsrv_connect().

Możliwe przyczyny i rozwiązania:

  • Rozszerzenie nie jest włączone w php.ini. Sprawdź, czy oba i extension=sqlsrvextension=pdo_sqlsrv są niekomentowane. Na Windows używaj pełnej nazwy pliku (extension=php_sqlsrv_84_ts_x64.dll). Szczegóły znajdziesz w sekcji Ładowanie sterowników.
  • Zła konstrukcja bezpieczeństwa gwintu. Binarny sterownik musi odpowiadać bezpieczeństwu wątków w twoim buildzie PHP (ts dla bezpieczeństwa wątkowego, nts dla nie-bezpieczeństwa w wątkach). Uruchom php -i | grep "Thread Safety" , aby sprawdzić. Pobierz pasujący binarny plik z strony pobierania.
  • Brakuje sterownika Microsoft ODBC. Sterowniki PHP oklejają sterownik Microsoft ODBC dla SQL Server. Na Linuksie i macOS zainstaluj msodbcsql18 (lub msodbcsql17) za pomocą menedżera pakietów przed załadowaniem rozszerzeń. Na Windows zainstaluj sterownik ODBC ze strony pobierania.

Sprawdź pomyślny montaż:

php -m | grep -i sqlsrv

Powinieneś zobaczyć zarówno to pdo_sqlsrv , jak i sqlsrv w wyjściu.

Instalacja PECL nie działa na Linuksie ani macOS

Objawy:

error: ‘SQL_HANDLE_DBC’ undeclared (first use in this function)
fatal error: 'sql.h' file not found

Poprawka:

Zainstaluj nagłówki rozwojowe ODBC przed uruchomieniem pecl install:

  • Ubuntu i Debian: sudo apt-get install unixodbc-dev
  • Red Hat, Fedora i CentOS:sudo dnf install unixODBC-devel
  • Alpine: apk add unixodbc-dev
  • macOS:brew install unixodbc

Następnie spróbuj ponownie:

sudo pecl install sqlsrv
sudo pecl install pdo_sqlsrv

Jeśli pecl po zamontowaniu nagłówek nadal się psuje, łańcuch narzędzi budowniczych może być niekompletny. Zainstaluj phpize, re2c, oraz kompilator C++ (build-essential na Debianie i Ubuntu, gcc-c++ make na Red Hat i Fedora, build-base na Alpine).

Pełną ścieżkę instalacji znajdziesz w poradniku instalacyjnym dla Linuksa i macOS.

Zainstalowano wiele wersji PHP

Objawy:

phpinfo() na serwerze WWW pokazuje jedną wersję PHP, ale php -v w wierszu poleceń inną, a sterownik jest załadowany tylko w jednej z nich.

Poprawka:

Każda wersja PHP ma własny php.iniext katalog. Znajdź właściwy plik php --ini konfiguracyjny w środowisku, w którym brakuje sterownika, i dodaj extension= tam linie. Po każdej php.ini zmianie ponownie uruchom serwer WWW (Apache, Nginx + PHP-FPM lub IIS).

Problemy z połączeniem

Nie można połączyć się z serwerem

Objawy:

SQLSTATE[08001]: [Microsoft][ODBC Driver 18 for SQL Server]TCP Provider: A connection attempt failed
SQLSTATE[HYT00]: [Microsoft][ODBC Driver 18 for SQL Server]Login timeout expired

Możliwe przyczyny i rozwiązania:

  • Serwer jest niedostępny. Sprawdź, czy nazwa serwera i port są poprawne. Z hosta PHP testuj surową łączność TCP.

    # Linux and macOS
    nc -vz <server>.database.windows.net 1433
    
    # Windows PowerShell
    Test-NetConnection -ComputerName <server>.database.windows.net -Port 1433
    
  • Zapora blokuje wychodzące 1433. Korporacyjne zapory sieciowe i chmurowe NSG często blokują port wychodzący 1433. Dodaj wyjątek lub pozwól na zakres IP Azure SQL Database dla swojego regionu.

  • Azure SQL server firewall. Dodaj publiczny adres IP klienta do reguł zapory na poziomie serwera w portalu Azure.

  • Nazwana instancja. Dla nazwanego przypadku sprawdź, czy usługa SQL Server Browser działa na serwerze i czy UDP 1434 jest otwarty. Albo połączyć się przez port zamiast po nazwie instancji.

Logowanie nie powiodło się

Objawy:

SQLSTATE[28000]: [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]Login failed for user '<user_id>'.

Możliwe przyczyny i rozwiązania:

  • Tryb uwierzytelniania SQL wyłączony. Lokalne instancje SQL Server domyślnie używają tylko uwierzytelniania Windows. Włącz uwierzytelnianie w trybie mieszanym w SQL Server Management Studio w sekcjiBezpieczeństwowłaściwości,> a następnie ponownie uruchom usługę SQL Server.
  • Azure SQL credentials format. Azure SQL wymaga w pełni kwalifikowanej nazwy użytkownika (user@servername) podczas łączenia się z narzędziami, które nie dodają jej automatycznie.
  • Użytkownik nie przypisany do bazy danych. Sprawdź, czy logowanie ma przypisanie użytkownika do docelowej bazy danych oraz czy użytkownik ma wymagane uprawnienia.
  • Wolę Microsoft Entra ID. Dla Azure SQL, Azure SQL Managed Instance oraz bazy danych SQL w Fabric używają uwierzytelniania Microsoft Entra (Authentication=ActiveDirectoryMsi, Authentication=ActiveDirectoryServicePrincipal, lub tokena dostępu) zamiast logowania SQL. Zobacz Nawiązywanie połączenia przy użyciu uwierzytelniania Microsoft Entra.

Nieprawidłowa wartość określona dla atrybutu parametry połączenia 'Authentication'

Objawy:

SQLSTATE[08001]: [Microsoft][ODBC Driver 17 for SQL Server]Invalid value specified for connection string attribute 'Authentication'

Przyczyna:

Sterownik ODBC zgłasza błąd, ale prawdziwym problemem jest to, do którego sterownika PDO_SQLSRV przypisany. Jeśli DSN nie zawiera Driver= słowa kluczowego, a host ma zainstalowane zarówno ODBC 17, jak i ODBC 18, PDO_SQLSRV może powiązać z starszą wersją. Starsze wersje ODBC 17.x nie znają nowszych Authentication wartości, takich jak ActiveDirectoryServicePrincipal lub ActiveDirectoryDefault, i wymagają nawet ActiveDirectoryMsi ODBC 17.3.1.1 lub nowszej wersji.

Poprawka:

Przypnij sterownik w DSN:

<?php
$dsn = "sqlsrv:Driver={ODBC Driver 18 for SQL Server};Server=$server;Database=$db;" .
       "Encrypt=true;Authentication=ActiveDirectoryMsi";
$conn = new PDO($dsn, null, null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);

Forma nawiasowa ({ODBC Driver 18 for SQL Server}) wychodzi poza przestrzeni w nazwie kierowcy. Sam komunikat o błędzie zawsze wskazuje sterownik, który go zgłosił, więc prefiks [Microsoft][ODBC Driver 17 for SQL Server] w błędzie jest najszybszym sposobem na potwierdzenie błędnego ograniczenia sterownika.

W ciągu DSN podano nieprawidłowe słowo kluczowe "UID"

Objawy:

SQLSTATE[IMSSP]: An invalid keyword 'UID' was specified in the DSN string.

Przyczyna:

PDO_SQLSRV wymusza listę dozwolonych słów kluczowych DSN i nie akceptuje ani PWD nie jest w UID DSN. PDO zarezerwuje argumenty drugiego i trzeciego konstruktora dla tych PDO_SQLSRV i tłumaczy je wewnętrznie na ODBC UID/PWD .

Poprawka:

Przenieś nazwę użytkownika (i hasło, do uwierzytelniania SQL) do konstruktora PDO:

<?php
// SQL authentication.
$dsn = "sqlsrv:Driver={ODBC Driver 18 for SQL Server};Server=$server;Database=$db;Encrypt=true";
$conn = new PDO($dsn, $user, $password);

// User-assigned managed identity. Pass the identity's client ID as $username.
$dsn = "sqlsrv:Driver={ODBC Driver 18 for SQL Server};Server=$server;Database=$db;" .
       "Encrypt=true;Authentication=ActiveDirectoryMsi";
$conn = new PDO($dsn, $clientId, null);

Sterownik proceduralny SQLSRV, w przeciwieństwie do tego, akceptuje UID i PWD w tablicy opcji połączenia przekazuje do sqlsrv_connect().

PDO_SQLSRV cicho ignoruje AccessToken w tablicy opcji

Objaw:

Masz token dostępu Microsoft Entra (na przykład z az account get-access-token --resource https://database.windows.net/, , lub ClientSecretCredential), i przekazujesz go do PDO_SQLSRV jak ['AccessToken' => $token] w czwartym argumentze ManagedIdentityCredentialkonstruktora. Próba połączenia kończy się niepowodzeniem z mylącym błędem, takim jak Windows logins are not supported in this version of SQL Server lub Login failed for user '', jakby nie podano żadnych danych uwierzytelniających.

Przyczyna:

Czwarty argument konstruktora w PDO jest zarezerwowany dla stałych atrybutów specyficznych dla sterownika (kluczy całkowitoliczbowe, takie jak PDO::ATTR_ERRMODE). PDO cicho usuwa wpisy z kluczem łańcuchowym, takie jak AccessToken, więc PDO_SQLSRV nigdy nie widzi tokena. Połączenie następnie wraca do uwierzytelniania Windows Zintegrowanego, którego serwer odrzuca.

Poprawka:

Przejdź AccessToken do ciągu DSN. Zarezerwuj tablicę opcji dla PDO::ATTR_* stałych.

<?php
$server = '<server>.database.windows.net';
$token  = getenv('SQL_ACCESS_TOKEN');   // raw JWT, no "Bearer " prefix

$dsn = "sqlsrv:Server=$server;Database=<database>;Encrypt=true;AccessToken=$token";
$conn = new PDO($dsn, null, null, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

Dodatkowe przykłady Microsoft Entra uwierzytelniania, w tym formularz DSN dla PDO_SQLSRV, zobacz Połącz za pomocą uwierzytelniania Microsoft Entra.

Dla proceduralnych SQLSRV należy AccessToken do tablicy informacji o połączeniach przekazywanej do sqlsrv_connect(), która faktycznie owija surowy JWT do dla SQL_COPT_SS_ACCESS_TOKEN ciebie:

<?php
$server = '<server>.database.windows.net';
$token  = getenv('SQL_ACCESS_TOKEN');   // raw JWT, no "Bearer " prefix

$connectionInfo = [
    'Database'               => '<database>',
    'AccessToken'            => $token,
    'Encrypt'                => true,
    'TrustServerCertificate' => false,
    'Driver'                 => '{ODBC Driver 18 for SQL Server}',
];

$conn = sqlsrv_connect($server, $connectionInfo);
if ($conn === false) {
    print_r(sqlsrv_errors());
    exit(1);
}

Błędy certyfikatów TLS

Objawy:

SQLSTATE[08001]: SSL Provider: The certificate chain was issued by an authority that is not trusted
SQLSTATE[08001]: SSL Provider: The target principal name is incorrect

Rozwiązania:

Wolę zaufany certyfikat. Używaj TrustServerCertificate=true tylko do lokalnego rozwoju na serwerze, który kontrolujesz.

Do rozwoju na podstawie certyfikatu podpisanego samodzielnie:

<?php
$server   = 'localhost';
$database = '<database>';
$user     = '<user_id>';
$password = '<password>';

$dsn = "sqlsrv:Server=$server;Database=$database;Encrypt=true;TrustServerCertificate=true";
$conn = new PDO($dsn, $user, $password, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

Caution

TrustServerCertificate=true wyłącza walidację certyfikatu serwera. Nigdy nie przenosz tego ustawienia do środowisk produkcyjnych, stagingowych czy współdzielonych.

Dla nazwy hosta produkcyjnego, która nie odpowiada nazwie Common Certificate (na przykład podczas łączenia przez listener), określ rzeczywisty podmiot certyfikatu:

<?php
$dsn = "sqlsrv:Server=<listener>;Database=<database>;Encrypt=true;HostNameInCertificate=*.database.windows.net;Authentication=ActiveDirectoryMsi";
$conn = new PDO($dsn, null, null, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

Przekroczenie limitu czasu połączenia

Objawy:

SQLSTATE[HYT00]: Login timeout expired

Możliwe przyczyny i rozwiązania:

  • LoginTimeout Nie ustawione ani zbyt niskie dla zimnego failoveru. Ustaw jawny LoginTimeout (w sekundach) w DSN podczas łączenia z Azure SQL. Awaryjne przełączania grupowe i bazy danych z zimnym startem mogą trwać dłużej niż pozwala na to krótki timeout po stronie klienta. Zobacz opcje połączenia dla odniesienia do opcji.
  • Bezczynny ponowny podłączenie do budżetu skrócony. Jeśli ustawisz ConnectRetryCount i ConnectRetryInterval, upewnij się, że LoginTimeout >= ConnectRetryCount * ConnectRetryInterval. W przeciwnym razie limit logowania kończy pętlę ponownego połączenia wcześniej. Zobacz odporność połączenia bezczynnego.
<?php
$dsn = "sqlsrv:Driver={ODBC Driver 18 for SQL Server};Server=<server>.database.windows.net;Database=<database>;" .
       "Encrypt=true;LoginTimeout=90;ConnectRetryCount=5;ConnectRetryInterval=15;" .
       "Authentication=ActiveDirectoryMsi";
$conn = new PDO($dsn, null, null, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

Problemy z wykonywaniem zapytań

Ciche awarie z PDO

Objaw:

Połączenie PDO::exec() OR PDOStatement::execute() wraca, false ale nie wyrzuca wyjątku.

Poprawka:

W wersji PHP 8.0 i nowszych domyślnym trybem PDO::ERRMODE_EXCEPTIONbłędu PDO jest . Jeśli wywołanie zwraca false bez rzutu, aplikacja zmienia tryb na PDO::ERRMODE_SILENT lub PDO::ERRMODE_WARNING. Ustawij go z powrotem na tryb wyjątku, aby niepowodzenia wywołały wyjątki:

<?php
$conn = new PDO($dsn, $user, $password, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);

Jeśli nie możesz globalnie zmienić trybu, sprawdź $conn->errorInfo() (lub $stmt->errorInfo()) po każdym połączeniu. Tablica zawiera [SQLSTATE, driver code, driver message].

Nieprawidłowa nazwa obiektu

Objawy:

SQLSTATE[42S02]: [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]Invalid object name 'Products'.

Możliwe przyczyny i rozwiązania:

  • Zły kontekst bazy danych. Sprawdź to szybkim pytaniem:

    <?php
    $stmt = $conn->query("SELECT DB_NAME()");
    echo $stmt->fetchColumn();
    
  • Brakuje kwalifikatora schematu. Używaj w pełni kwalifikowanych nazw, aby uniknąć zależności od domyślnego schematu dzwoniącego:

    SELECT * FROM dbo.Products;
    
  • Wielkość liter. Bazy danych tworzone przy użyciu sortowania na podstawie wielkich liter traktują products i Products jako różne obiekty. Zrównaj dokładny przypadek z definicji tabeli.

Błędna liczba parametrów

Objawy:

SQLSTATE[HY093]: Invalid parameter number
SQLSTATE[07002]: COUNT field incorrect or syntax error

Poprawka:

Dla PDO_SQLSRV liczba zastępców ? musi odpowiadać liczbie wartości przekazywanych do execute(), a każdy ? wiąże pojedynczy skalar (nie tablicę). Dla parametrów nazwanych każdy w :name SQL musi pojawić się w tablicy i odwrotnie.

<?php
$stmt = $conn->prepare(
    "SELECT * FROM dbo.Products WHERE CategoryID = ? AND ListPrice > ?"
);
$stmt->execute([1, 50.0]);
foreach ($stmt as $row) {
    // ...
}

Dla SQLSRV przekażmy tablicę parametrów do sqlsrv_query() lub sqlsrv_prepare():

<?php
$stmt = sqlsrv_query(
    $conn,
    "SELECT * FROM dbo.Products WHERE CategoryID = ? AND ListPrice > ?",
    [1, 50.0]
);
if ($stmt === false) {
    die(print_r(sqlsrv_errors(), true));
}

Szersze wprowadzenie do wiązania parametrów można znaleźć w artykule Wykonuj zapytania parametryzowane.

Emulacja PDO przygotowuje błędy maski

Objawy:

Instrukcja wykonuje się pomyślnie na jednym połączeniu, ale powoduje błąd składniowy na innym połączeniu, które używa tego samego tekstu zapytania.

Przyczyna:

PDO_SQLSRV obsługuje zarówno emulowane, jak i natywne przygotowane instrukcje. Emulacja przygotowuje (PDO::ATTR_EMULATE_PREPARES = true) interpoluje parametry po stronie klienta. Natywne przygotowuje (false) wysyła zapytanie i parametry osobno do serwera. Zachowanie różni się dla TOP (?), parametrów tabelowych oraz niektórych przypadków brzegowych w typowej przymusze.

Poprawka:

Preferuję lokalne produkty w produkcji. Ustaw PDO::ATTR_EMULATE_PREPARES => false czas połączenia, aby zachowanie było spójne w różnych środowiskach:

<?php
$conn = new PDO($dsn, null, null, [
    PDO::ATTR_ERRMODE          => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => false,
]);

Szczegóły dotyczące stosowania każdego trybu można znaleźć w PDO::p repare.

Problemy z typem danych

Znaki Unicode pojawiają się jako ? lub zniekształcone

Objawy:

Wiersze zapisywane przez PHP zawierają znaki zapytania lub znaki zastępcze zamiast oryginalnych znaków nie-ASCII. Czyta i zwraca zniekształcony tekst.

Możliwe przyczyny i rozwiązania:

  • Typ kolumny to VARCHAR, nie NVARCHAR. kolumny varchar używają strony kodowej, a nie Unicode. Użyj nvarchar do tekstów międzynarodowych.

  • Brakuje wskazówki kodowania UTF-8 na PDO_SQLSRV. Gdy kolumna SQL Server to nvarchar, a dane PHP to UTF-8, powiedz sterownikowi, aby konwertował między UTF-8 (klient) a UTF-16 (serwer):

    <?php
    $conn = new PDO(
        "sqlsrv:Server=<server>;Database=<database>;Encrypt=true",
        $user,
        $password,
        [
            PDO::ATTR_ERRMODE                    => PDO::ERRMODE_EXCEPTION,
            PDO::SQLSRV_ATTR_ENCODING            => PDO::SQLSRV_ENCODING_UTF8,
        ]
    );
    
  • Sterownik SQLSRV: zażądaj UTF-8 wyraźnie. SQLSRV_ENC_CHAR to domyślna 8-bitowa strona kodowa systemu, a nie UTF-8. Dla UTF-8 z SQLSRV ustaw "CharacterSet" => "UTF-8" na połączenie i przekaż literal 'UTF-8' na SQLSRV_PHPTYPE_STRING on fetch lub bind. Zobacz Wyślij i pobierz dane UTF-8.

Błędy konwersji daty i godziny

Objawy:

SQLSTATE[22007]: Invalid character value for cast specification

Poprawka:

Na PDO_SQLSRV nie wiązaj surowego obiektu DateTime . PDO stringuje wartości ograniczenia przed powiązaniem, a PHP nie DateTime ma __toString() metody, więc execute([new DateTime(...)]) podnosi Object of class DateTime could not be converted to string. Najpierw sformatuj wartość lub przekaż ciąg ISO 8601 (YYYY-MM-DD HH:MM:SS[.fff]), a nie łańcuch sformatowany lokalnie.

<?php
$stmt = $conn->prepare("INSERT INTO dbo.Events (EventDate) VALUES (?)");
$stmt->execute([(new DateTime("2026-03-15 10:00:00"))->format("Y-m-d H:i:s.u")]);

Aby pobrać kolumny datetime jako DateTime obiekty zamiast ciągów znaków na PDO_SQLSRV, ustaw atrybut instrukcji:

<?php
$stmt = $conn->prepare("SELECT EventDate FROM dbo.Events");
$stmt->setAttribute(PDO::SQLSRV_ATTR_FETCHES_DATETIME_TYPE, true);
$stmt->execute();

Szczegóły można znaleźć w artykule Pobierz obiekty czasu datowego (PDO_SQLSRV).

Problemy z formatowaniem dziesiętnym

Objawy:

Wartości między -1 a 1 nie mają wiodącego zera, a wartości pieniężne i drobne mają nieoczekiwaną liczbę miejsc po przecinku.

Poprawka:

PDO_SQLSRV zawsze pobiera wartości dziesiętne i liczbowe jako ciągi znaków z ich dokładną precyzją i skalą. Ustaw PDO::SQLSRV_ATTR_FORMAT_DECIMALS tak, by dodawać wiodące zero do wartości między -1 a 1:

<?php
$conn->setAttribute(PDO::SQLSRV_ATTR_FORMAT_DECIMALS, true);

PDO::SQLSRV_ATTR_DECIMAL_PLACES Dotyczy tylko pieniędzy i wartości drobnych pieniędzy . Ustawia skalę wyświetlaną od 0 do 4 i może zaokrąglać wyświetlaną wartość. Nie wpływa to na wartości dziesiętne ani liczbowe .

Szczegóły można znaleźć w Formatowanie dziesiętnych i pieniędzy (PDO_SQLSRV) lub Formatowanie dziesiętnych i pieniądza (SQLSRV).

Problemy transakcyjne

Zmiany danych nie utrzymują się

Objawy:

Wiersze, które wstawiasz lub aktualizujesz w PHP, nie pojawiają się podczas zapytania z innej sesji.

Przyczyna:

PDO::beginTransaction() otwiera jawną transakcję, która wymaga jawnego commit(). Jeśli skrypt PHP zakończy się bez wywołania commit(), PDO cofa transakcję podczas czyszczenia połączenia.

Poprawka:

Zawsze paruj beginTransaction() z commit(), i używaj try/catch do cofnięcia błędu:

<?php
try {
    $conn->beginTransaction();
    $conn->exec("INSERT INTO dbo.Orders (CustomerID, Total) VALUES (1, 100)");
    $conn->exec("UPDATE dbo.Inventory SET Stock = Stock - 1 WHERE ProductID = 5");
    $conn->commit();
} catch (PDOException $e) {
    $conn->rollBack();
    throw $e;
}

Dla SQLSRV używaj sqlsrv_begin_transaction, sqlsrv_commit, oraz sqlsrv_rollback.

Błędy zakleszczeń

Objawy:

SQLSTATE[40001]: [Microsoft][ODBC Driver 18 for SQL Server][SQL Server]Transaction (Process ID 62) was deadlocked

Poprawka:

Obsługa przejściowych błędów zablokowania za pomocą logiki powtórek. Opakuj całą transakcję (nie tylko instruację failing), aby wcześniejsze instrukcje odtwarzały się na świeżej transakcji. Aby uzyskać wzorzec powtórek zorientowany na produkcję – zobacz przykład na stronie docelowej sterownika PHP.

Powtarzające się zakleienia wskazują na problem projektowy. Uchwyć graf blokad i przeanalizować, które instrukcje i typy blokad są zaangażowane. Typowe poprawki obejmują zmianę kolejności operacji, tak aby konkurencyjne transakcje zdobywały blokady w tej samej sekwencji, ograniczanie zakresu transakcji oraz dodawanie indeksów skracających czas blokady. Pełny poradnik znajdziesz w przewodniku Deadlocks.

Problemy z odpornością połączeń

Ponowne połączenie się nie zdarza

Objawy:

Połączenie bezczynne pozostaje przerwane po awaryjnym przełączaniu Azure SQL Database, mimo że ustawisz ConnectRetryCount i ConnectRetryInterval.

Możliwe przyczyny i rozwiązania:

  • Aktywny kursor po stronie serwera. Odporność na bezczynne połączenia ponownie łączy tylko bezczynne. Otwarty kursor po stronie serwera lub oczekująca transakcja utrzymuje połączenie aktywne. Uwolnić kursory po stronie serwera, używając sqlsrv_free_stmt() or $stmt = null; (PDO) przed oknem failover, albo przełączyć się na kursor buforowany po stronie klienta. Zobacz odporność połączenia bezczynnego.
  • Stan sesji nieodwracalny. Niektórych stanów sesji nie da się przywrócić, w tym tabel tymczasowych, kursorów globalnych i lokalnych, kontekstu transakcji, blokad aplikacji, EXECUTE AS/REVERT, uchwytów automatyzacji OLE, przygotowanych uchwytów XML oraz flag śledzenia. Każdy z tych stanów sesji uniemożliwia automatyczne ponowne połączenie.
  • LoginTimeout za mały. Jeśli ConnectRetryCount * ConnectRetryInterval > LoginTimeout, sterownik przestaje próbować ponownie, gdy LoginTimeout zostanie osiągnięty. Podbij, LoginTimeout aby pokryć cały budżet na ponowne próby.

Problemy z wydajnością

Aby rozpoznać i naprawić wolne zapytania, zimne starty, duże zbiory wyników oraz wkładki zbiorcze, zobacz Performance tuning.

Włącz diagnostykę sterowników

Gdy wywołania na poziomie error_log() aplikacji nie dostarczają wystarczających informacji, włącz logowanie po stronie kierowcy. Raportuje każde połączenie ODBC, które wykonuje kierowca.

PDO_SQLSRV

Ustaw pdo_sqlsrv.log_severity i php.ini zrestartuj serwer WWW. To ustawienie jest czytelne tylko podczas inicjalizacji:

[pdo_sqlsrv]
pdo_sqlsrv.log_severity = 1

Wartości to 0 (wyłączone, domyślne), -1 (błędy, ostrzeżenia i powiadomienia), 1 (błędy), 2 (ostrzeżenia) oraz 4 (powiadomienia).

SQLSRV

Włącz logowanie w czasie wykonywania za pomocą sqlsrv_configure():

<?php
sqlsrv_configure("LogSubsystems", SQLSRV_LOG_SYSTEM_CONN | SQLSRV_LOG_SYSTEM_STMT);
sqlsrv_configure("LogSeverity", SQLSRV_LOG_SEVERITY_ERROR | SQLSRV_LOG_SEVERITY_WARNING);

Wpisy dziennika prowadzą do pliku skonfigurowanego przez error_log .php.ini Pełną listę podsystemów i skali nasilenia można znaleźć w artykule Aktywność logowania.

Problemy z kontenerami i układami scalonymi

Brakujące biblioteki systemowe na Linuksie

Objawy:

error while loading shared libraries: libodbc.so.2: cannot open shared object file
error while loading shared libraries: libssl.so.1.1: cannot open shared object file

Poprawka:

Zainstaluj zależności w czasie działania przed instalacją sterownika PHP:

Dystrybucja Zainstaluj polecenie
Ubuntu i Debian sudo apt-get install unixodbc libgssapi-krb5-2
Red Hat i Fedora sudo dnf install unixODBC krb5-libs
Alpine apk add unixodbc gcompat

Następnie instaluj msodbcsql18 z repozytorium pakietów Microsoft. Aby poznać repozytoria pakietów i wersje specyficzne dla dystrybucji, zobacz przewodnik instalacji sterowników ODBC.

Budowanie obrazów Dockera kończy się sukcesem, ale połączenia zawodzą w czasie wykonywania

Objawy:

Obraz się buduje i uruchamia PHP, ale PDO::__construct() wyświetla błąd sterownika ODBC – nie-znaleziony.

Poprawka:

Sprawdź, czy sterownik ODBC jest zainstalowany w obrazie runtime, a nie tylko na etapie budowy. Zainstaluj msodbcsql18 i unixodbc-dev na tym samym etapie, co wysyła się do produkcji. W budowie wieloetapowej instaluj je na ostatnim etapie. Jednoetapowa instalacja oparta na Debianie wygląda tak:

# Pin to a specific PHP minor version in production, for example php:8.4.11-cli.
FROM php:8.4-cli
RUN apt-get update && apt-get install -y --no-install-recommends \
        curl gnupg2 apt-transport-https ca-certificates \
    && curl -sSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /usr/share/keyrings/microsoft.gpg \
    && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft.gpg] https://packages.microsoft.com/debian/12/prod bookworm main" > /etc/apt/sources.list.d/mssql-release.list \
    && apt-get update \
    && ACCEPT_EULA=Y apt-get install -y --no-install-recommends msodbcsql18 unixodbc-dev \
    # $PHPIZE_DEPS ships in the official php image and includes gcc, make, autoconf, and re2c.
    && apt-get install -y --no-install-recommends $PHPIZE_DEPS \
    && pecl install sqlsrv pdo_sqlsrv \
    && docker-php-ext-enable sqlsrv pdo_sqlsrv \
    && apt-get purge -y --auto-remove $PHPIZE_DEPS \
    && rm -rf /var/lib/apt/lists/*