Advanced Pagination for MySQL(mysql高级分页)
在叶子的文章里谈到了使用innerjoin从而减少了对page的扫描也就是减少了所谓的回表例如:
SELECT*FROM`t1`INNERJOIN(SELECTidFROM`t1`ORDERBYidDESCLIMIT935500,10)t2USING(id)
通过直接对id的操作而不是整张表的扫描通过id的join抓出符合条件id然后通过ID再去做数据的抓取。这样就避免了对不需要的页面的扫描。
不过这样也不是最佳的方法还可以通过对id的range更加缩小范围例如:
我们要分100条记录分一页可以写成
$page_size=100select*fromtwhereid>99orderbyidasclimit$page_size;select*from twhereid>199orderbyidasclimit$page_size;
尽量避免limitM,N这种写法mysql在对M值很大而offset很小的时候的处理方式很不人性化,所以尽量不要使用offset来取得特定行数。
在这里有一个问题比如根据不是唯一索引的column分页那么可能存在一个问题,例如一个列column1存在11个key=100的值那么你使用limitN之后取到的minvalue还是同一个值
这种情况如何处理?给个例子:
比如要每10条记录分一页
select*fromt orderbycolumn1desc limit10
注意这里取到的minvalue还是100(11个连续的100)对下面的分页会产生影响,如何处理?
雅虎给出的方案非常好取一个extra的column例如PK或者uniqueindexkey例如:
select*fromt orderbycolumn1desc,iddesc limit10--第一个页 select*fromt wherecolumn1<=minvalue_col1and(id<minvalue_idorcolumn1<minvalue_col1)limit10 ---第二个页
这样就确保了唯一性保证了每页的数据不会重复思想就是通过add一个唯一的extra取得这个extra的边界值结合rangecolumn来进行分页。
这个SQL还能被优化成:
SELECTm2.*FROMtm1,tm2 WHEREm1.id=m2.id ANDm1.column1<=minvalue_col1 AND(m1.id<minvalue_idORm1.column1<minvalue_col1) ORDERBYm1.column1DESC,m1.idDESC LIMIT10;
核心思想:通过extra过滤配合ID扫描避免大量的回表操作这样就达到了要取多少条就扫描多少条(inpage)