第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就不需要了。
一些算总数的相关代码如下:
SQL:
//查两个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)
PHP:
1 /* 获得总数,相当于count(*) */ 2 function queryGetTotal($minID, $maxID, $deleteIDArr) 3 { 4 //排序 5 sort($deleteIDArr); 6 $num=0; 7 foreach ($deleteIDArr as $v) { 8 if ($v>=$minID && $v<=$maxID) { 9 $num++; 10 } 11 } 12 return $maxID-$num-$minID+1; 13 }
PHP:
1 /*根据最小ID和需要显示的行数查找最大ID,deleteIDArr是记录删除的ID*/ 2 function queryGetMaxID($minID, $rowNum, $deleteIDArr) 3 { 4 //排序 5 sort($deleteIDArr); 6 7 //预估最大id 8 $max = $minID+$rowNum-1; 9 10 //没有删除的直接返回预估 11 if (!count($deleteIDArr)) { 12 return $max; 13 } 14 15 //只有一个 16 if (count($deleteIDArr)==1) { 17 if($deleteIDArr[0]<=$max){ 18 return $max+1; 19 } 20 if($deleteIDArr[0]>$max){ 21 return $max; 22 } 23 } 24 25 //循环查出 26 if (count($deleteIDArr)>1) { 27 28 $num=0; 29 $fMax=0; 30 31 foreach ($deleteIDArr as $k=>$v) { 32 if($v>=$minID){ 33 $num++; 34 } 35 //如果超出预估 36 if ($v-$num>=$max) { 37 $fMax = $v; 38 break; 39 } 40 } 41 42 //没有满足任何条件 43 if (!$fMax) { 44 return $max+$num; 45 } 46 47 //刚好等于预估值或大于 48 if ($fMax-$num==$max) { 49 return $fMax; 50 }else if ($fMax-$num>$max) { 51 return $max+$num; 52 }else{ 53 return $max+$num; 54 } 55 } 56 }
至此,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],用算法自动维护一下,至此就变得无比完美了,如果这个算法实现了记得评论分享给我,以后有时间再研究这个算法。
这可能是比较完美的方案之一,就是麻烦了点,就是需要多写几个方法,分页多带个参数,再写个算法。
本方案只适合大表中少许被删数据,表id不连续的情况下使用,对了,本方法仅做学习交流只用,如果使用此方法出问题不负责噢,千万记得备份数据库。