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

SQLクエリをどのように管理しますか

    あなたにとって最善の行動方針は、データアクセスにどのように取り組んでいるかによって異なります。採用できるアプローチは3つあります。

    • ストアドプロシージャを使用する
    • クエリをコードに保持します(ただし、前述のように、すべてのクエリを関数に入れ、パラメーターにPDOを使用するようにすべてを修正します)
    • ORMツールを使用する

    独自の生のSQLをデータベースエンジンに渡したい場合は、PHPコードから生のSQLを取得するだけで、比較的変更を加えないようにするだけで、ストアドプロシージャを使用できます。ストアドプロシージャと生のSQLの議論は少し聖戦ですが、K。Scott Allenは、データベースのバージョン管理

    私はストアドプロシージャを使用しない傾向があります。私は、DBにストアドプロシージャを通じて公開されたAPIがあるプロジェクトに取り組んできましたが、ストアドプロシージャには独自の制限が課せられる可能性があり、それらのプロジェクトにはすべて 、程度の差はあれ、動的に生成された生のSQLをコードで使用してDBにアクセスしました。

    DB上にAPIレイヤーを設定すると、DBチームと開発チームの間の責任をより適切に描写できますが、クエリがコードに保持されている場合の柔軟性がいくらか犠牲になりますが、PHPプロジェクトのサイズが大きくなる可能性は低くなります。この描写から利益を得るのに十分なチーム。

    概念的には、データベースをバージョン管理する必要があります。ただし、実際には、データベースをバージョン管理するよりも、コードだけをバージョン管理する可能性がはるかに高くなります。コードに変更を加えるときにクエリを変更する可能性がありますが、データベースに対して格納されているストアドプロシージャのクエリを変更する場合は、コードをチェックインするときにそれらをチェックインしない可能性があり、アプリケーションの重要な領域でのバージョン管理の利点の多く。

    ただし、ストアドプロシージャを使用しないことを選択したかどうかに関係なく、少なくとも、各データベース操作がページの各スクリプトに埋め込まれるのではなく、独立した関数に格納されていることを確認する必要があります。これは、基本的にDBのAPIレイヤーです。コードで維持およびバージョン管理されます。ストアドプロシージャを使用している場合、これは事実上、DBに2つのAPIレイヤーがあることを意味します。1つはコードを使用し、もう1つはDBを使用します。プロジェクトに個別のチームがない場合、不必要に複雑になる可能性があります。確かにそうです。

    問題がコードの整理の問題である場合、SQLが詰まったコードをより見やすくする方法があります。次に示すUserManagerクラスは、開始するのに適した方法です。このクラスには、「user」テーブルに関連するクエリのみが含まれます。各クエリにはクラス内に独自のメソッドがあり、クエリはprepareステートメントにインデントされ、ストアドプロシージャでフォーマットするのと同じようにフォーマットされます。

    // UserManager.php:
    
    class UserManager
    {
        function getUsers()
        {
            $pdo = new PDO(...);
            $stmt = $pdo->prepare('
                SELECT       u.userId as id,
                             u.userName,
                             g.groupId,
                             g.groupName
                FROM         user u
                INNER JOIN   group g
                ON           u.groupId = g.groupId
                ORDER BY     u.userName, g.groupName
            ');
            // iterate over result and prepare return value
        }
    
        function getUser($id) {
            // db code here
        }
    }
    
    // index.php:
    require_once("UserManager.php");
    $um = new UserManager;
    $users = $um->getUsers();
    foreach ($users as $user) echo $user['name'];
    

    ただし、クエリが非常に似ているが、複雑なページング、並べ替え、フィルタリングなど、クエリ条件に膨大な数の順列がある場合は、既存のコードをオーバーホールするプロセスではありますが、オブジェクト/リレーショナルマッパーツールがおそらく最適な方法です。ツールを利用するのは非常に複雑になる可能性があります。

    ORMツールを調査する場合は、Propel を確認する必要があります。 、Yii のActiveRecordコンポーネント 、またはキングパパPHP ORM、 Doctrine 。これらはそれぞれ、あらゆる種類の複雑なロジックを使用して、データベースへのクエリをプログラムで構築する機能を提供します。 Doctrineは最も完全な機能を備えており、ネストされたセットなどを使用してデータベースをテンプレート化できます。ツリーパターン 箱から出して。

    パフォーマンスの点では、ストアドプロシージャが最速ですが、一般的に生のSQLをはるかに上回っていません。 ORMツールは、非効率的または冗長なクエリ、各リクエストでORMライブラリをロードする際の巨大なファイルIO、各クエリでの動的SQL生成など、さまざまな点でパフォーマンスに大きな影響を与える可能性があります。これらすべてが影響を与える可能性がありますが、 ORMツールを使用すると、手動クエリを使用して独自のDBレイヤーを作成するよりも、はるかに少ないコードで利用できる電力を大幅に増やすことができます。

    Gary Richardson ただし、コードでSQLを引き続き使用する場合は、クエリを使用しているかストアドプロシージャを使用しているかに関係なく、常にPDOのプリペアドステートメントを使用してパラメーターを処理する必要があります。入力のサニタイズはPDOによって実行されます。

    // optional
    $attrs = array(PDO::ATTR_PERSISTENT => true);
    
    // create the PDO object
    $pdo = new PDO("mysql:host=localhost;dbname=test", "user", "pass", $attrs);
    
    // also optional, but it makes PDO raise exceptions instead of 
    // PHP errors which are far more useful for debugging
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    
    $stmt = $pdo->prepare('INSERT INTO venue(venueName, regionId) VALUES(:venueName, :regionId)');
    $stmt->bindValue(":venueName", "test");
    $stmt->bindValue(":regionId", 1);
    
    $stmt->execute();
    
    $lastInsertId = $pdo->lastInsertId();
    var_dump($lastInsertId);
    

    警告:IDが1であると仮定すると、上記のスクリプトはstring(1) "1"を出力します。 。 PDO->lastInsertId() 実際の列が整数であるかどうかに関係なく、IDを文字列として返します。 PHPは文字列から整数へのキャストを自動的に実行するため、これが問題になることはおそらくないでしょう。

    以下はbool(true)を出力します :

    // regular equality test
    var_dump($lastInsertId == 1); 
    

    ただし、 is_intのように、値が整数であることを期待しているコードがある場合 またはPHPの「本当に、本当に、100%等しい」 演算子:

    var_dump(is_int($lastInsertId));
    var_dump($lastInsertId === 1);
    

    いくつかの問題が発生する可能性があります。

    編集: ストアドプロシージャに関するいくつかの良い議論ここ



    1. Oracleデータベースのすべてのビューを一覧表示する方法

    2. メインテーブルの列の値に応じてテーブルを結合します

    3. Oracle:UPSERTの方法(更新するか、テーブルに挿入しますか?)

    4. sql with-recursiveステートメントはどのように解釈されますか?