站長資訊網
        最全最豐富的資訊網站

        ThinkPHP5水平分表后分頁查詢解決方案

        ThinkPHP5內置了partition方法,可用于實現簡單的分表。新增,修改,刪除,查詢單條數據時,用partition方法都可以輕松搞定,因為這些操作有一個共同的特點,就是能事先明確的知道,我要操作的是哪一條記錄。但有一個需求,ThinkPHP5似乎沒有解決,比如當一個大表,被拆分成若干個子表時,如何根據相關條件及排序獲取分頁數據。

        這種需求場景下,由于事先并不知道哪些數據會出現在第一頁,哪些數據會出現在第二頁,這些根據檢索條件動態匹配的列表數據,該如何查詢呢?

        一次失敗的嘗試

        最先想到的也是最直接的一種方式,就是將partition方法和paginate方法結合起來,看似順理成章的事,結果悲劇了,數據庫被搞得直接奔潰。究其原因,要想實現分頁查詢,partition方法中需要union若干個子表,而且每個union的子表中,都是select * 的形式,這樣就會嚴重影響到查詢的效率,況且,在獲取記錄總數的時候,也完全沒必要查詢出所有字段。

        成功之道

        既然select * 會影響效率,那么select 出主鍵會怎樣呢?當然是相當的快!總體思路就是分兩次獲取數據,第一次先查詢出主鍵,然后第二次,根據主鍵,獲取對應的數據。具體實現如下:

        核心思想

        水平分表后,當需要分頁獲取數據時,效率會變得非常低下,拆分的子表越多,對查詢性能的影響就會越大。所以核心思想就是,盡量通過主鍵id來獲取對應的數據記錄,也就是分兩次來獲取列表數據。

        1. 先查詢總記錄數及主鍵id

        該步驟中,union 子表的select語句中,只需要列出主鍵id和其它額外必須的字段即可,不相關的字段無需出現。

        2. 根據主鍵id查詢對應的完整數據。

        函數封裝

        1. 構造獲取總記錄數及主鍵ID的sql子查詢語句

        /**  * 構造獲取總記錄數及主鍵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; }

        調用方式:

        假設buildPartitionSql函數的執行結果為$tables,那么完整的SQL語句如下:

        獲取總記錄數的完整sql:

        select count(1) as total from .$tables['countSql']

        獲取主鍵id的完整sql:

        select * from .$tables['listSql']. limit 0,10

        2. 構造獲取指定id對應記錄的sql子查詢語句

        /**  * 構造獲取指定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; }

        調用方式:

        假設buildPartitionListSql函數的執行結果為$sql,那么完整的SQL語句如下:

        select * from .$sql

        注意:業務層面的所有檢索條件,都放在了第一步的union子句中,第二步只需要根據id拿數據就行了。

        php中文網,大量的免費thinkphp入門教程,歡迎在線學習!

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 国产精品一区二区久久精品| 久久精品无码一区二区三区免费 | 97久久综合精品久久久综合| 欧美成人精品高清在线播放| 亚洲天堂久久精品| 99久久久精品免费观看国产| 亚洲精品无码不卡在线播放HE| 国产免费伦精品一区二区三区| 国产精品亚洲精品| 国产女人精品视频国产灰线| 亚洲精品无码MV在线观看| 久久久久九九精品影院| 国产精品偷伦视频免费观看了 | 国产高清国内精品福利99久久| 国产欧美日韩精品a在线观看| 亚洲精品一级无码鲁丝片| 久久精品无码av| 欧美成人精品欧美一级乱黄一区二区精品在线 | 国产在线国偷精品免费看| 久久精品9988| 高清在线亚洲精品国产二区| 精品不卡一区二区| 亚洲AV无码国产精品色午友在线| 人妻无码精品久久亚瑟影视| 久久99精品免费一区二区| 国产精品视频不卡| 国产精品成人无码久久久久久| 欧美激情精品久久久久| 国产精品第13页| 国产精品99久久久久久人| 99精品高清视频一区二区| 国产福利精品一区二区| 国精无码欧精品亚洲一区| 久久精品aⅴ无码中文字字幕重口| 午夜精品久久久久久久| 欧美精品黑人粗大免费| 久久久久久夜精品精品免费啦| 无码精品国产一区二区三区免费 | 午夜精品久视频在线观看| 色偷偷888欧美精品久久久| 91人前露出精品国产|