mysql count(*)、limit分頁慢的終極解決方案新鮮出爐


省略一切閑言碎語直接上方案。

 

第1步:建一個表,命名為 test,一個id字段,再加一個content內容字段吧;

第2步:往test里塞1000萬條數據,當然你也可以塞10億條,哈哈哈哈哈;

第3步:建一個表:命名為 table_delete_id_aggregate,三個字段,id、did(刪除的id),tableName(刪除數據的表名稱);

第4步:test表刪除數據時需要往table_delete_id_aggregate表中記錄被刪除id和數據表名(如果是連續的id,最好存成[1,10000],假設1到10000的數據都刪了,不必存10000條數據);

第5步:test表添加數據時,需要從table_delete_id_aggregate中隨意獲得一個已刪除的id,用來填補已經缺失的id,添加成功后從table_delete_id_aggregate中刪除這個id,目的是為了減少table_delete_id_aggregate的數據量以及讓A表的id變得更連續(這個有個問題得從[1,10000]中拆出一個數,然后再更新一下變成[1,9999]);

第6步:test表查詢時,需要先查出這個查詢條件的最小id,得到這個id后,需要用到一個方法,用來找到數據之間存在多少斷點,譬如已經刪除的id值為1、2、3、4、5、6、7、8、9、10、30、300、1000,最小id是1,分頁需要往后取10條數據,需要遍歷一下這個已刪除的數組,找到滿足取10條的最大id值,並統計出哪些id已經刪除了,獲得總數,然后交給查詢語句between minid and maxid查出所需的10條數據,limit就不需要了。

 

一些算總數的相關代碼如下

//查兩個id之間間隔的數的sql語句
select * from ((select id as minID from data_info where id>0 limit 1) as a, (select id as maxID from data_info where id>0 order by id desc limit 1) as b)

  

/* 獲得總數,相當於count(*) */
	function queryGetTotal($minID, $maxID, $deleteIDArr)
	{
	    //排序
	    sort($deleteIDArr);
	    $num=0;
	    foreach ($deleteIDArr as $v) {
	        if ($v>=$minID && $v<=$maxID) {
	            $num++;
	        }
	    }
	    return $maxID-$num-$minID+1;
	}

  

/*根據最小ID和需要顯示的行數查找最大ID,deleteIDArr是記錄刪除的ID*/
	function queryGetMaxID($minID, $rowNum, $deleteIDArr)
	{
		//排序
		sort($deleteIDArr);
		
		//預估最大id
		$max = $minID+$rowNum-1;
		
		//沒有刪除的直接返回預估
		if (!count($deleteIDArr)) {
			return $max;
		}
		
		//只有一個
		if (count($deleteIDArr)==1) {
			if($deleteIDArr[0]<=$max){
				return $max+1;
			}
			if($deleteIDArr[0]>$max){
				return $max;
			}
		}
		
		//循環查出
		if (count($deleteIDArr)>1) {
			
			$num=0;
			$fMax=0;
			
			foreach ($deleteIDArr as $k=>$v) {
				if($v>=$minID){
					$num++;
				}
				//如果超出預估
				if ($v-$num>=$max) {
					$fMax = $v;
					break;
				}
			}

			//沒有滿足任何條件
			if (!$fMax) {
				return $max+$num;
			}
			
			//剛好等於預估值或大於
			if ($fMax-$num==$max) {
				return $fMax;
			}else if ($fMax-$num>$max) {
				return $max+$num;
			}else{
				return $max+$num;
			}
		}
	}

  

  

至此,10億+的mysql表,就再也沒有count(*)、limit查詢語句性能差效率低問題了,親測1億+的數據,查詢和分頁都是毫秒級的。當然,這種方法只適合在帶查詢的分頁時使用,不過別的場景應該也沒有多大問題哈哈哈哈哈~`

補充:請求時需要加個參數maxID的參數,第二頁時用於當作between minid and maxid中的minid)甚至可以把第一次查的總數帶上,這樣就不需要執行查總數的sql和方法了。

 

啊!又免費為社會廣大人民做貢獻了,希望數據庫公司不會因此而倒閉~·唯一不足就是需要記錄一下已經刪除的id和新增id時使用舊的id,查詢時多了個語句.......

目前我刪除的id是用php文件預存的數組,一般已經徹底刪除的數據行不會太多,如果用這種方法你的數據表刪除的id很多,那就沒辦法了,1億條數據的表刪除數量別超過100萬條應該問題不大~`。但即使如此,也有解,譬如1---1億條之間的數據間隔,不必存1億個id,可以用數組[1,100000000]表示,上面第4、5步有說明,最好在添加、刪除時用算法處理一下,這樣記錄刪除表的輸出的數組就會變得很小,最終輸出可能就是[1,20],[22,34],[20,90],用算法自動維護一下,至此就變得無比完美了,如果這個算法實現了記得評論分享給我,我很累得休息下,以后有時間再研究這個算法。。。

這可能是比較完美的方案之一,甚至沒有之一了,就是麻煩了點,但不用分表不香嗎?就是多寫幾個方法,分頁多帶個參數,再寫個算法,code就這么runding了.....

 

本方案只適合大表中少許被刪數據,表id不連續的情況下使用,對了,本方法僅做學習交流只用,如果使用此方法出問題不負責噢,千萬記得備份數據庫。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM