sql >> データベース >  >> RDS >> Mysql

PDO MySQL:PDO ::ATTR_EMULATE_PREPARESを使用するかどうか?

    あなたの懸念に答えるには:

    1. MySQL> =5.1.17(またはPREPAREの場合は>=5.1.21 およびEXECUTE ステートメント)クエリキャッシュでプリペアドステートメントを使用できます 。したがって、MySQL + PHPのバージョンでは、クエリキャッシュでプリペアドステートメントを使用できます。ただし、MySQLドキュメントでクエリ結果をキャッシュする際の注意事項に注意してください。キャッシュできないクエリや、キャッシュしても役に立たないクエリにはさまざまな種類があります。私の経験では、クエリキャッシュは、とにかくそれほど大きな勝利にはならないことがよくあります。クエリとスキーマは、キャッシュを最大限に活用するために特別な構築が必要です。多くの場合、アプリケーションレベルのキャッシュは、長期的にはとにかく必要になります。

    2. ネイティブの準備はセキュリティに何の違いもありません。疑似プリペアドステートメントは引き続きクエリパラメータ値をエスケープします。バイナリプロトコルを使用するMySQLサーバーではなく、文字列を使用してPDOライブラリで実行されます。つまり、同じPDOコードは、EMULATE_PREPARESに関係なく、インジェクション攻撃に対して同等に脆弱(または脆弱ではない)になります。 設定。唯一の違いは、パラメータの置換が発生する場所です。EMULATE_PREPARESを使用します。 、PDOライブラリで発生します。 EMULATE_PREPARESなし 、MySQLサーバーで発生します。

    3. EMULATE_PREPARESなし 実行時ではなく準備時に構文エラーが発生する可能性があります。 EMULATE_PREPARESを使用 PDOには実行時までMySQLに提供するクエリがないため、実行時にのみ構文エラーが発生します。 これは、作成するコードに影響することに注意してください !特にPDO::ERRMODE_EXCEPTIONを使用している場合 !

    追加の考慮事項:

    • prepare()には固定費がかかります (ネイティブのプリペアドステートメントを使用)、したがってprepare();execute() ネイティブのプリペアドステートメントを使用すると、エミュレートされたプリペアドステートメントを使用してプレーンなテキストクエリを発行するよりも少し遅くなる可能性があります。多くのデータベースシステムでは、prepare()のクエリプラン もキャッシュされ、複数の接続で共有される可能性がありますが、MySQLがこれを行うとは思いません。したがって、プリペアドステートメントオブジェクトを複数のクエリに再利用しないと、全体的な実行が遅くなる可能性があります。

    最終的な推奨事項として 、MySQL + PHPの古いバージョンでは、プリペアドステートメントをエミュレートする必要があると思いますが、ごく最近のバージョンでは、エミュレーションをオフにする必要があります。

    PDOを使用するアプリをいくつか作成した後、最適な設定と思われるPDO接続機能を作成しました。おそらく、このようなものを使用するか、好みの設定に微調整する必要があります:

    /**
     * Return PDO handle for a MySQL connection using supplied settings
     *
     * Tries to do the right thing with different php and mysql versions.
     *
     * @param array $settings with keys: host, port, unix_socket, dbname, charset, user, pass. Some may be omitted or NULL.
     * @return PDO
     * @author Francis Avila
     */
    function connect_PDO($settings)
    {
        $emulate_prepares_below_version = '5.1.17';
    
        $dsndefaults = array_fill_keys(array('host', 'port', 'unix_socket', 'dbname', 'charset'), null);
        $dsnarr = array_intersect_key($settings, $dsndefaults);
        $dsnarr += $dsndefaults;
    
        // connection options I like
        $options = array(
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
        );
    
        // connection charset handling for old php versions
        if ($dsnarr['charset'] and version_compare(PHP_VERSION, '5.3.6', '<')) {
            $options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES '.$dsnarr['charset'];
        }
        $dsnpairs = array();
        foreach ($dsnarr as $k => $v) {
            if ($v===null) continue;
            $dsnpairs[] = "{$k}={$v}";
        }
    
        $dsn = 'mysql:'.implode(';', $dsnpairs);
        $dbh = new PDO($dsn, $settings['user'], $settings['pass'], $options);
    
        // Set prepared statement emulation depending on server version
        $serverversion = $dbh->getAttribute(PDO::ATTR_SERVER_VERSION);
        $emulate_prepares = (version_compare($serverversion, $emulate_prepares_below_version, '<'));
        $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, $emulate_prepares);
    
        return $dbh;
    }
    


    1. 1億2000万件のレコードを更新する最速の方法

    2. PostgreSQLで列のデフォルト値を変更するにはどうすればよいですか?

    3. MySQLNOTINクエリ

    4. SQL Server(T-SQL)で「date」を「smalldatetime」に変換する例