ThinkPHP5水平分表后分頁(yè)查詢解決方案

thinkphp5內(nèi)置了partition方法,可用于實(shí)現(xiàn)簡(jiǎn)單的分表。新增,修改,刪除,查詢單條數(shù)據(jù)時(shí),用partition方法都可以輕松搞定,因?yàn)檫@些操作有一個(gè)共同的特點(diǎn),就是能事先明確的知道,我要操作的是哪一條記錄。但有一個(gè)需求,thinkphp5似乎沒(méi)有解決,比如當(dāng)一個(gè)大表,被拆分成若干個(gè)子表時(shí),如何根據(jù)相關(guān)條件及排序獲取分頁(yè)數(shù)據(jù)。

這種需求場(chǎng)景下,由于事先并不知道哪些數(shù)據(jù)會(huì)出現(xiàn)在第一頁(yè),哪些數(shù)據(jù)會(huì)出現(xiàn)在第二頁(yè),這些根據(jù)檢索條件動(dòng)態(tài)匹配的列表數(shù)據(jù),該如何查詢呢?

一次失敗的嘗試

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

成功之道

立即學(xué)習(xí)PHP免費(fèi)學(xué)習(xí)筆記(深入)”;

既然select * 會(huì)影響效率,那么select 出主鍵會(huì)怎樣呢?當(dāng)然是相當(dāng)?shù)目欤】傮w思路就是分兩次獲取數(shù)據(jù),第一次先查詢出主鍵,然后第二次,根據(jù)主鍵,獲取對(duì)應(yīng)的數(shù)據(jù)。具體實(shí)現(xiàn)如下:

核心思想

水平分表后,當(dāng)需要分頁(yè)獲取數(shù)據(jù)時(shí),效率會(huì)變得非常低下,拆分的子表越多,對(duì)查詢性能的影響就會(huì)越大。所以核心思想就是,盡量通過(guò)主鍵id來(lái)獲取對(duì)應(yīng)的數(shù)據(jù)記錄,也就是分兩次來(lái)獲取列表數(shù)據(jù)。

1. 先查詢總記錄數(shù)及主鍵id

該步驟中,union 子表的select語(yǔ)句中,只需要列出主鍵id和其它額外必須的字段即可,不相關(guān)的字段無(wú)需出現(xiàn)。

2. 根據(jù)主鍵id查詢對(duì)應(yīng)的完整數(shù)據(jù)。

函數(shù)封裝

1. 構(gòu)造獲取總記錄數(shù)及主鍵ID的sql子查詢語(yǔ)句

/** ?*?構(gòu)造獲取總記錄數(shù)及主鍵ID的sql子查詢語(yǔ)句 ?*?@param?$table?主表名稱(chēng) ?*?@param?$idKey?主鍵id字段名稱(chēng) ?*?@param?string?$fields?其它字段名稱(chēng),多個(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??$countTable,?'listSql'?=>?$listTable]; ????return?$tables; }

調(diào)用方式:

假設(shè)buildPartitionSql函數(shù)的執(zhí)行結(jié)果為$tables,那么完整的SQL語(yǔ)句如下:

獲取總記錄數(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子查詢語(yǔ)句

/** ?*?構(gòu)造獲取指定id對(duì)應(yīng)記錄的sql子查詢語(yǔ)句 ?*?@param?$table?主表名稱(chēng) ?*?@param?$idKey?指定的id字段名稱(chēng) ?*?@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?<p>調(diào)用方式:</p><p>假設(shè)buildPartitionListSql函數(shù)的執(zhí)行結(jié)果為$sql,那么完整的SQL語(yǔ)句如下:</p><pre class="brush:php;toolbar:false">select?*?from?.$sql

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

php中文網(wǎng),大量的免費(fèi)thinkphp入門(mén)教程,歡迎在線學(xué)習(xí)!

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊6 分享