您好,登錄后才能下訂單哦!
這篇文章主要介紹了ThinkPHP5水平分表后分頁查詢?cè)趺磁?,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
ThinkPHP5內(nèi)置了partition方法,可用于實(shí)現(xiàn)簡(jiǎn)單的分表。新增,修改,刪除,查詢單條數(shù)據(jù)時(shí),用partition方法都可以輕松搞定,因?yàn)檫@些操作有一個(gè)共同的特點(diǎn),就是能事先明確的知道,我要操作的是哪一條記錄。但有一個(gè)需求,ThinkPHP5似乎沒有解決,比如當(dāng)一個(gè)大表,被拆分成若干個(gè)子表時(shí),如何根據(jù)相關(guān)條件及排序獲取分頁數(shù)據(jù)。
這種需求場(chǎng)景下,由于事先并不知道哪些數(shù)據(jù)會(huì)出現(xiàn)在第一頁,哪些數(shù)據(jù)會(huì)出現(xiàn)在第二頁,這些根據(jù)檢索條件動(dòng)態(tài)匹配的列表數(shù)據(jù),該如何查詢呢?
一次失敗的嘗試
最先想到的也是最直接的一種方式,就是將partition方法和paginate方法結(jié)合起來,看似順理成章的事,結(jié)果悲劇了,數(shù)據(jù)庫被搞得直接奔潰。究其原因,要想實(shí)現(xiàn)分頁查詢,partition方法中需要union若干個(gè)子表,而且每個(gè)union的子表中,都是select * 的形式,這樣就會(huì)嚴(yán)重影響到查詢的效率,況且,在獲取記錄總數(shù)的時(shí)候,也完全沒必要查詢出所有字段。
成功之道
既然select * 會(huì)影響效率,那么select 出主鍵會(huì)怎樣呢?當(dāng)然是相當(dāng)?shù)目?!總體思路就是分兩次獲取數(shù)據(jù),第一次先查詢出主鍵,然后第二次,根據(jù)主鍵,獲取對(duì)應(yīng)的數(shù)據(jù)。具體實(shí)現(xiàn)如下:
核心思想
水平分表后,當(dāng)需要分頁獲取數(shù)據(jù)時(shí),效率會(huì)變得非常低下,拆分的子表越多,對(duì)查詢性能的影響就會(huì)越大。所以核心思想就是,盡量通過主鍵id來獲取對(duì)應(yīng)的數(shù)據(jù)記錄,也就是分兩次來獲取列表數(shù)據(jù)。
1. 先查詢總記錄數(shù)及主鍵id
該步驟中,union 子表的select語句中,只需要列出主鍵id和其它額外必須的字段即可,不相關(guān)的字段無需出現(xiàn)。
2. 根據(jù)主鍵id查詢對(duì)應(yīng)的完整數(shù)據(jù)。
函數(shù)封裝
1. 構(gòu)造獲取總記錄數(shù)及主鍵ID的sql子查詢語句
/** * 構(gòu)造獲取總記錄數(shù)及主鍵ID的sql子查詢語句 * @param $table 主表名稱 * @param $idKey 主鍵id字段名稱 * @param string $fields 其它字段名稱,多個(gè)字段用英文逗號(hào)分隔 * @param int $num 子表數(shù)量 * @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; }
調(diào)用方式:
假設(shè)buildPartitionSql函數(shù)的執(zhí)行結(jié)果為$tables,那么完整的SQL語句如下:
獲取總記錄數(shù)的完整sql:
select count(1) as total from .$tables['countSql']
獲取主鍵id的完整sql:
select * from .$tables['listSql']. limit 0,10
2. 構(gòu)造獲取指定id對(duì)應(yīng)記錄的sql子查詢語句
/** * 構(gòu)造獲取指定id對(duì)應(yīng)記錄的sql子查詢語句 * @param $table 主表名稱 * @param $idKey 指定的id字段名稱 * @param $idValues 指定的id字段值 * @param int $num 子表數(shù)量 * @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; }
調(diào)用方式:
假設(shè)buildPartitionListSql函數(shù)的執(zhí)行結(jié)果為$sql,那么完整的SQL語句如下:
select * from .$sql
注意:業(yè)務(wù)層面的所有檢索條件,都放在了第一步的union子句中,第二步只需要根據(jù)id拿數(shù)據(jù)就行了。
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“ThinkPHP5水平分表后分頁查詢?cè)趺磁边@篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。