함수 실행 비교

PHP 드라이버 다운로드

두 드라이버 모두 문을 한 번만 실행하거나 반복 실행을 위해 문을 준비할 수 있습니다. 사용자가 제공한 값에 대한 매개변수를 사용하세요, 쿼리를 한 번만 실행하더라도 말이죠.

실행 API는 결과를 가져오는 방법과 별도로 선택하세요. 쿼리를 준비한다고 해서 해당 행들을 가져오지 않고, 결과를 버퍼링해도 쿼리가 매개변수화되지는 않습니다. 다음 예시들은 읽기 전용 쿼리를 한 번 준비하고, 서로 다른 값으로 두 번 실행한 뒤, 다음 실행 전에 각 결과를 소모합니다.

실행 스타일 SQLSRV PDO_SQLSRV
매개변수 없이 한 번 쿼리를 실행해 보세요 sqlsrv_query 결과에는 PDO::query를, 영향받은 행 수에는 PDO::exec를 사용합니다
매개변수와 함께 쿼리를 한 번 실행하세요 sqlsrv_query($conn, $sql, $params) PDO::prepare() 다음 PDOStatement::execute()
한 번 준비하고, 다양한 조건으로 반복해서 실행하세요 sqlsrv_prepare + sqlsrv_execute PDO::prepare + PDOStatement::execute

sqlsrv_query() 한 번의 호출로 준비 및 실행을 수행하며, statement 리소스를 반환합니다. sqlsrv_prepare() 실행 없이 문장 자원을 반환합니다; 각 실행마다 sqlsrv_execute()를 호출하십시오. PDO의 query()는 실행하여 PDOStatement반환하며, exec()는 결과 객체 대신 영향을 받은 행 수를 반환합니다. 성공한 exec()은(는) === false을 반환할 수 있으므로, 실패 반환은 0가 아니라 if (!$count)와 비교하십시오.

PDO::query() 매개변수 값 배열을 받아들이지 않습니다. 해당 항목의 선택적 인수는 가져오기를 구성합니다. 매개변수화된 PDO_SQLSRV 쿼리의 경우 execute() 및 prepare()를 사용하세요.

한 번 준비하면 문장 핸들을 다른 값으로 재사용할 수 있습니다. 이것이 서버가 실행 계획을 절대 다시 컴파일하지 않는다는 보장은 아닙니다. PDO_SQLSRV는 기본적으로 준비된 실행을 사용하며, 여기에는 PDO::query()의 경우도 포함됩니다. 직접 쿼리 속성은 그 별도의 선택을 제어합니다.

한 번 준비하고 반복해서 실행합니다

이들은 별개의 완전한 명령줄 프로그램입니다. 선택한 확장 프로그램을 설치하고 불러온 다음, PHP 프로세스 환경에서 SQL_DATABASE, SQL_USER, SQL_PASSWORD, SQL_SERVER를 설정합니다. SQL Server 테스트 데이터베이스와 클라이언트가 신뢰하는 서버 인증서를 사용하세요. 환경 설정과 비밀번호 없는 대안에 대해서는 서버에 접속하기를 참조하세요.

실제 데이터베이스 이름, 사용자 이름, 비밀번호를 환경 변수에 저장하세요. 두 프로그램 모두 PHP 드라이버의 ODBC 스타일 연결 처리에 따라 닫는 중괄호(})를 두 번 쓰고 각 값을 중괄호로 감싸서 이 값들을 한 번 이스케이프합니다. 연결 값 이스케이프 처리는 쿼리 매개변수 바인딩과는 별개입니다.

이 프로그램들은 테이블을 생성하거나 데이터를 변경하지 않고 두 개의 인라인 행에 대한 Transact-SQL(T-SQL) 쿼리를 실행합니다. 각 프로그램을 별도의 .php 파일에 저장하고 php <file>로 실행합니다. 샘플 데이터베이스는 필요하지 않습니다.

SQLSRV

&$productId를 $productId와 함께 참조로 전달합니다. 각 sqlsrv_execute()은 현재 값을 사용합니다. SQLSRV_FETCH_ASSOC 열 이름으로 키핑된 배열을 반환합니다. null 결과는 더 이상 행이 없음을 의미하며, false 오류를 나타냅니다.

<?php
$config = [];
foreach (['SQL_SERVER', 'SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
    $value = getenv($name);
    if ($value === false || $value === '') {
        throw new RuntimeException("Set $name before running this example.");
    }
    $config[$name] = $value;
}
foreach (['SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
    $config[$name] = '{' . str_replace('}', '}}', $config[$name]) . '}';
}
$conn = sqlsrv_connect($config['SQL_SERVER'], [
    'Database' => $config['SQL_DATABASE'],
    'UID' => $config['SQL_USER'],
    'PWD' => $config['SQL_PASSWORD'],
    'Encrypt' => true,
    'TrustServerCertificate' => false,
    'LoginTimeout' => 30,
    'CharacterSet' => 'UTF-8',
]);
if ($conn === false) {
    throw new RuntimeException(print_r(sqlsrv_errors(), true));
}

$sql = "SELECT Name FROM (VALUES (1, 'Bike'), (2, 'Helmet')) AS Product(ProductId, Name) WHERE ProductId = ?";
$productId = 1;
$stmt = null;
try {
    $stmt = sqlsrv_prepare($conn, $sql, [&$productId], ['QueryTimeout' => 30]);
    if ($stmt === false) {
        throw new RuntimeException(print_r(sqlsrv_errors(), true));
    }
    foreach ([1 => 'Bike', 2 => 'Helmet'] as $productId => $expected) {
        if (!sqlsrv_execute($stmt)) {
            throw new RuntimeException(print_r(sqlsrv_errors(), true));
        }
        $names = [];
        while (($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) !== null) {
            if ($row === false) {
                throw new RuntimeException(print_r(sqlsrv_errors(), true));
            }
            $names[] = $row['Name'];
        }
        if ($names !== [$expected]) {
            throw new RuntimeException('Expected exactly one matching product.');
        }
        echo $names[0], PHP_EOL;
    }
} finally {
    if (is_resource($stmt)) {
        sqlsrv_free_stmt($stmt);
    }
    sqlsrv_close($conn);
}

PDO_SQLSRV

bindParam()와 한 번만 $productId 바인딩하세요. 각 execute()는 현재 값을 읽습니다. PDO::PARAM_INT 매개변수의 PHP/PDO 바인딩 타입을 지정합니다; 결과에서 가져온 열의 PHP 타입을 제어하지 않습니다. 데이터베이스 오류가 빈 결과로 오인되지 않고 실행을 중단하도록 예외 모드를 설정하세요.

<?php
$config = [];
foreach (['SQL_SERVER', 'SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
    $value = getenv($name);
    if ($value === false || $value === '') {
        throw new RuntimeException("Set $name before running this example.");
    }
    $config[$name] = $value;
}
foreach (['SQL_DATABASE', 'SQL_USER', 'SQL_PASSWORD'] as $name) {
    $config[$name] = '{' . str_replace('}', '}}', $config[$name]) . '}';
}
$server = $config['SQL_SERVER'];
$database = $config['SQL_DATABASE'];
$pdo = new PDO(
    "sqlsrv:Server=$server;Database=$database;Encrypt=true;"
    . "TrustServerCertificate=false;LoginTimeout=30",
    $config['SQL_USER'],
    $config['SQL_PASSWORD'],
    [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::SQLSRV_ATTR_ENCODING => PDO::SQLSRV_ENCODING_UTF8,
    ]
);
$sql = "SELECT Name FROM (VALUES (1, 'Bike'), (2, 'Helmet')) AS Product(ProductId, Name) WHERE ProductId = ?";
$stmt = null;
try {
    $stmt = $pdo->prepare($sql, [PDO::SQLSRV_ATTR_QUERY_TIMEOUT => 30]);
    $productId = 1;
    $stmt->bindParam(1, $productId, PDO::PARAM_INT);
    foreach ([1 => 'Bike', 2 => 'Helmet'] as $productId => $expected) {
        $stmt->execute();
        $names = $stmt->fetchAll(PDO::FETCH_COLUMN);
        if ($names !== [$expected]) {
            throw new RuntimeException('Expected exactly one matching product.');
        }
        echo $names[0], PHP_EOL;
        $stmt->closeCursor();
    }
} finally {
    $stmt = null;
    $pdo = null;
}

각 예시는 다음을 출력합니다:

Bike
Helmet

PDO execute()에 전달된 배열의 값은 PDO::PARAM_STR로 처리됩니다. SQL이 정수 매개변수(예: 매개변수화된 TOP 카운트)를 요구할 때, bindValue() 배열을 호출 PDO::PARAM_INT 한 후 배열 없이 호출 execute() 합니다.

쿼리를 변경하지 않고 값을 할당할 수 있습니다

매개변수 마커는 테이블 이름, 열명, 키워드, 정렬 방향이 아니라 값을 나타냅니다. ? 주위에 따옴표를 넣지 마세요. 동적 식별자 또는 ASC/DESC의 경우, 신뢰할 수 없는 텍스트를 연결하는 대신 애플리케이션 제어 허용 목록에서 선택하세요. IN 목록의 경우, 값당 하나의 마커를 제공하세요.

Requirement SQLSRV PDO_SQLSRV
한 번의 실행에 대한 값 바인딩 sqlsrv_query()에 매개변수 배열을 전달합니다. execute() 후에 prepare()에 배열을 전달하거나 먼저 값을 묶으세요.
변수의 현재 값을 재사용 &$variable를 sqlsrv_prepare()에 전달되는 배열에 포함하세요. execute()를 변수와 함께 호출한 다음, 배열 없이 bindParam()를 호출합니다. PHP는 변수를 참조로 전달합니다; 호출 지점에 &를 추가하지 마세요.
결합 시점에 값을 묶으세요 실행을 위해 매개변수 배열의 값을 사용하세요. 호출하면 bindValue(); 이후 원본 변수에 대한 변경은 그 바인딩된 값을 변경하지 않습니다.
정수 입력을 지정하세요 명시적 타입이 필요할 때는 SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_INT 및 SQLSRV_SQLTYPE_INT와 함께 매개변수 디스크립터를 사용하세요. PDO::PARAM_INT와 결합하세요. 위치 bindParam() 및 bindValue() 인덱스는 1부터 시작하며 0부터 시작하지 않습니다.
SQL 전송 NULL 작업에 필요할 경우 PHP null를 명시적 SQL 형식으로 바인딩하세요. PDO::PARAM_NULL와 결합하세요.
출력 매개변수 받기 SQLSRV_PARAM_OUT 또는 SQLSRV_PARAM_INOUT와 함께 참조된 변수를 사용하세요. 필요한 유형과 길이와 함께 bindParam()와 PDO::PARAM_INPUT_OUTPUT를 사용하세요.

prepared statement를 실행하는 동안 참조된 변수들을 유효한 상태로 유지하세요. SQLSRV 프로그램은 매개변수 배열을 교체하는 대신 바운드 변수를 변경합니다. PDO 프로그램은 바인딩 후 배열 없이 의도적으로 execute()를 호출합니다; 배열 기반 실행과 이 패턴을 혼동하지 마세요.

저장 프로시저의 출력 값은 프로시저 결과를 완성하는 등 별도의 처리가 필요합니다. 이러한 입력 전용 예시에서 출력 매개변수 동작을 추론하지 마세요. 자세한 내용은 방향 매개변수 사용법을 참조하세요.

실행 및 가져오기 동작 구성

Setting SQLSRV PDO_SQLSRV
실행 타임아웃 QueryTimeout 문 옵션 배열에 있습니다. PDO::SQLSRV_ATTR_QUERY_TIMEOUT 연결이나 문에서.
이름이 지정된 결과 키 SQLSRV_FETCH_ASSOC이(가) sqlsrv_fetch_array()에 전달되었습니다. PDO::FETCH_ASSOC fetch 메서드로 전달되거나 연결의 기본 fetch 모드로 설정된
정방향 전용 결과 기본 커서; 순서대로 가져오기. 기본 커서; 순서대로 가져오기.
클라이언트 버퍼링 결과 Scrollable => SQLSRV_CURSOR_CLIENT_BUFFERED; PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL와 PDO::SQLSRV_ATTR_CURSOR_SCROLL_TYPE => PDO::SQLSRV_CURSOR_BUFFERED.
직접 실행 대 준비된 실행 PDO 직접 쿼리 속성도 없습니다. 통합 sqlsrv_query() 호출 또는 명시적 준비/실행 쌍을 선택하세요. PDO::SQLSRV_ATTR_DIRECT_QUERY 드라이버의 기본 준비 실행 대신 직접 실행을 선택합니다.
매개변수 에뮬레이션 PDO 에뮬레이션 속성은 없습니다. PDO::ATTR_EMULATE_PREPARES 는 direct-query 속성과 별개입니다. 올바른 유형을 바인딩하는 대신 그것을 사용하지 마세요.

예시들은 작은 결과를 제공합니다. fetchAll() 모든 행을 PHP 메모리에 로드합니다; 큰 결과를 위해 fetch loop를 사용합니다. 일치하는 결과를 반환하지 않는 쿼리는 실행 오류가 아닙니다. SQLSRV는 결과의 종료를 sqlsrv_fetch_array()에서 null로 보고하고, PDO는 fetch()에서 false로 보고합니다. 가져온 행 내 SQL NULL 은 여전히 PHP null입니다.

행 수만 SELECT 을 성공 체크로 삼지 마세요. 순방향 전용 커서는 버퍼링되거나 스크롤 가능한 커서와 같은 행 수 기능을 제공하지 않습니다. 필요한 행을 불러오고 세거나, 별도의 COUNT 쿼리를 사용하세요. 커서별 옵션과 제한 사항에 대해서는 커서 유형 지정 및 행 선택을 참조하세요.

실패 처리 및 완료 결과

SQLSRV 준비, 실행, 가져오기 작업을 각각 확인하세요. prepare가 성공했다고 해서 실행이 성공하는 것은 아닙니다: 서버는 실행 시점에 매개변수 값, 권한 또는 SQL 문을 거부할 수 있습니다. 작업이 sqlsrv_errors()을(를) 반환하면 즉시 false 캡처합니다. SQLSRV는 기본적으로 많은 경고를 오류로 처리하므로 전체 컬렉션을 점검하세요.

PDO의 경우, 예외 모드에서 연결 실패와 데이터베이스 오류가 발생하면 PDOException를 throw합니다. 보호된 애플리케이션 진단에서 SQLSTATE 및 드라이버 오류 정보를 검사하고; HTTP 응답에서 예외 텍스트나 자격 증명을 반환하지 마세요. prepare() 성공했다고 해서 해당 문이 이미 실행되었다는 증거는 아닙니다.

증상 Action
모든 실행은 첫 번째 값을 사용합니다 SQLSRV의 경우, 참조로 변수를 바인딩하세요. PDO의 경우, 변경되는 변수에는 bindParam()를 사용하거나 새 값마다 bindValue()를 호출하세요.
카운트와 같은 수치 매개변수는 거부됩니다. 필요한 정수 타입을 명시적으로 바인딩하세요. PDO execute([$value]) 는 PHP 값이 정수라도 문자열 매개변수를 사용합니다.
두 번째 명령은 대기 중인 결과를 보고합니다 결과를 소비하거나 해제한 후 연결을 재사용하세요. PDO는 남은 결과가 필요 없을 때 사용 closeCursor() 하세요.
기대 출력 파라미터는 변하지 않았습니다 모든 프로시저 결과 항목을 작성하고 매개변수 방향, PHP 타입, 출력 버퍼 길이를 검증합니다.
메모리 사용량은 결과 크기에 따라 증가합니다 fetchAll() 또는 불필요한 클라이언트 버퍼링을 순차적 가져오기로 대체하세요.

예제들은 finally에서 해당 문을 해제하고 연결을 종료합니다. 그들은 거래를 시작하지 않습니다. 여러 쓰기가 함께 커밋되거나 모두 롤백해야 할 때는 명시적 트랜잭션 을 사용하세요. 준비된 구문을 재사용한다고 해서 쓰기 기록이 트랜잭션으로 묶이지 않습니다.

대상 및 구현 차이

prepare/execute API와 PHP 참조 규칙은 확장 기능과 PHP/PDO에 속합니다. SQL 타겟은 어떤 T-SQL 문과 타입을 지원할지 결정하며, ODBC가 기본 통신을 수행합니다. 한 번 준비하면 반복 작업을 줄일 수 있지만, 특정 서버 실행 계획이나 속도 향상을 보장하지는 않습니다.

입력 바인딩 패턴은 SQL Server, Azure SQL Database, Azure SQL Managed Instance, Azure Synapse Analytics, Microsoft Fabric의 SQL 데이터베이스, Microsoft Fabric의 Warehouse에 적용됩니다. 이 프로그램들은 SQL Server에 연결할 때 SQL 인증을 사용합니다. Azure 온보딩 시, Microsoft Entra authentication을 선호하세요. Fabric 제품 모두 이를 요구하며, Warehouse 역시 다중 활성 결과 세트(MARS)를 비활성화해야 합니다. SQL Server 코드를 재사용하기 전에 선택한 대상의 스키마 변경, 트랜잭션, 저장 프로시저 지원 여부를 확인하세요. 엔드포인트와 인증 차이에 대해서는 Azure와 Fabric 연결을 참조하세요.