zoukankan      html  css  js  c++  java
  • 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不连续的情况下使用,对了,本方法仅做学习交流只用,如果使用此方法出问题不负责噢,千万记得备份数据库。

  • 相关阅读:
    [CQOI2006]凸多边形
    NOIP后省选集训前文化课划水记
    FFT字符串匹配
    ghj1222的代码规范
    博弈论
    P1350 车的放置
    P2110 欢总喊楼记
    虫食算
    3192: [JLOI2013]删除物品
    逛公园
  • 原文地址:https://www.cnblogs.com/tie123abc/p/14053676.html
Copyright © 2011-2022 走看看