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('SELECT %s FROM %s_%s where 1=1 %s', $idKey, $table, ($i + 1), $where); $listTable[] = sprintf('SELECT %s FROM %s_%s where 1=1 %s', $fieldStr,$table, ($i + 1), $where); } $countTable = '( ' . implode(" UNION ", $countTable) . ') AS ' . $table; $listTable = '( ' . implode(" UNION ", $listTable) . ') AS ' . $table; $tables = ['countSql' => $countTable, 'listSql' => $listTable]; return $tables; }
select count(1) as total from .$tables['countSql']
select * from .$tables['listSql']. limit 0,10
/** * 构造获取指定id对应记录的sql子查询语句 * @param $table 主表名称 * @param $idKey 指定的id字段名称 * @param $idValues 指定的id字段值 * @param int $num 子表数量 * @return string */ function buildPartitionListSql($table,$idKey,$idValues,$num=1) { $sql = ''; $ids = is_array($idValues) ? implode(',',$idValues) : $idValues; if ($ids) { $listTable = []; for ($i = 0; $i < $num; $i++) { $listTable[] = sprintf('SELECT * FROM %s_%s where %s in (%s)', $table, ($i + 1), $idKey, $ids); } $sql = '( ' . implode(" UNION ", $listTable) . ') AS ' . $table; } return $sql; }
select * from .$sql
thinkphp 入門チュートリアル 、オンライン学習へようこそ!
以上が水平テーブル分割後の ThinkPHP5 ページング クエリ ソリューションの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。