ホームページ  >  記事  >  PHPフレームワーク  >  水平テーブル分割後の ThinkPHP5 ページング クエリ ソリューション

水平テーブル分割後の ThinkPHP5 ページング クエリ ソリューション

藏色散人
藏色散人転載
2019-12-31 13:17:573101ブラウズ

ThinkPHP5 には、単純なテーブル パーティションを実装するために使用できるパーティション メソッドが組み込まれています。単一のデータを追加、変更、削除、またはクエリする場合、これらの操作には共通の特徴があり、操作するレコードを事前に明確に把握できるため、パーティション メソッドを簡単に使用できます。しかし、ThinkPHP5 では解決できそうにないニーズ、たとえば、大きなテーブルが複数のサブテーブルに分割されている場合、関連する条件とソートに基づいてページング データを取得する方法などがあります。

この需要シナリオでは、最初のページにどのデータが表示され、2 ページ目にどのデータが表示されるかが事前にわからないため、検索条件は?

#失敗した試み

最初に思い浮かぶ最も直接的な方法は、パーティション メソッドとページネーション メソッドを組み合わせるというものです。それは論理的だと思われます。結果は悲劇的でした。 、データベースが直接クラッシュしました。その理由は、ページング クエリを実装するには、パーティション メソッドで複数のサブテーブルを結合する必要があり、各結合のサブテーブルが select * の形式になっており、クエリの効率に重大な影響を与えるためです。レコードを取得するとき 合計数を計算するとき、すべてのフィールドをクエリする必要はまったくありません。

成功への道のり

select * は効率に影響するため、主キーが選択されるとどうなるでしょうか?もちろんかなり速いですよ!一般的な考え方は、データを 2 つのステップで取得することです。1 回目は主キーをクエリし、2 回目は主キーに基づいて対応するデータを取得します。具体的な実装は次のとおりです。

Core Idea

テーブルを水平分割した後、データをページ単位で取得する必要がある場合、効率が非常に低くなります。より多くのサブテーブルが分割されると、クエリのパフォーマンスへの影響が大きくなります。したがって、中心となるアイデアは、主キー ID を通じて対応するデータ レコードを取得しようとすること、つまりリスト データを 2 回取得することです。

1. 最初にレコードの総数と主キー ID をクエリします

このステップでは、ユニオン サブテーブルの select ステートメントで、主キー ID とその他の追加情報をリストするだけで済みます。いいえ 関連するフィールドは存在する必要はありません。

2. 主キー ID に基づいて、対応する完全なデータをクエリします。

関数のカプセル化

1. SQL サブクエリ ステートメントを構築して、レコードの総数と主キー ID

/**
 * 构造获取总记录数及主键ID的sql子查询语句
 * @param $table 主表名称
 * @param $idKey 主键id字段名称
 * @param string $fields 其它字段名称,多个字段用英文逗号分隔
 * @param int $num 子表数量
 * @param string $where 查询条件
 * @return array
 */
function buildPartitionSql($table,$idKey,$fields='',$num=1,$where='') {
    $countTable = [];
    $listTable = [];
    $fieldList = [$idKey];
    if ($fields) {
        $fieldList = array_merge($fieldList,explode(',',$fields));
        $fieldList = array_unique($fieldList);
    }
    $fieldStr = implode(',',$fieldList);
    for ($i = 0; $i < $num; $i++) {
        $countTable[] = sprintf(&#39;SELECT %s FROM %s_%s where 1=1 %s&#39;, $idKey, $table, ($i + 1), $where);
        $listTable[] = sprintf(&#39;SELECT %s FROM %s_%s where 1=1 %s&#39;, $fieldStr,$table, ($i + 1), $where);
    }
    $countTable = &#39;( &#39; . implode(" UNION ", $countTable) . &#39;) AS &#39; . $table;
    $listTable = &#39;( &#39; . implode(" UNION ", $listTable) . &#39;) AS &#39; . $table;
    $tables = [&#39;countSql&#39; => $countTable, &#39;listSql&#39; => $listTable];
    return $tables;
}

呼び出しメソッド:

buildPartitionSql 関数の実行結果が $tables であると仮定すると、完全な SQL ステートメントは次のようになります:

レコードの合計数の完全な SQL を取得します:

select count(1) as total from .$tables[&#39;countSql&#39;]

主キー ID の完全な SQL を取得します:

select * from .$tables[&#39;listSql&#39;]. limit 0,10

2. SQL サブクエリ ステートメントを構築して、指定された ID

/**
 * 构造获取指定id对应记录的sql子查询语句
 * @param $table 主表名称
 * @param $idKey 指定的id字段名称
 * @param $idValues 指定的id字段值
 * @param int $num 子表数量
 * @return string
 */
function buildPartitionListSql($table,$idKey,$idValues,$num=1) {
    $sql = &#39;&#39;;
    $ids = is_array($idValues) ? implode(&#39;,&#39;,$idValues) : $idValues;
    if ($ids) {
        $listTable = [];
        for ($i = 0; $i < $num; $i++) {
            $listTable[] = sprintf(&#39;SELECT * FROM %s_%s where %s in (%s)&#39;, $table, ($i + 1), $idKey, $ids);
        }
        $sql = &#39;( &#39; . implode(" UNION ", $listTable) . &#39;) AS &#39; . $table;
    }
    return $sql;
}

に対応するレコードを取得します。メソッドの呼び出し:

と仮定します。 buildPartitionListSql 関数の実行結果が $sql である場合、完全な SQL ステートメントは次のとおりです:

select * from .$sql

注: ビジネス レベルのすべての検索条件は、最初のステップの Union 句に配置されます。 2 番目のステップでは、ID に基づいてデータを取得するだけです。

php 中国語 Web サイト、多数の無料の

thinkphp 入門チュートリアル 、オンライン学習へようこそ!

以上が水平テーブル分割後の ThinkPHP5 ページング クエリ ソリューションの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。