遅いと制限クエリの最適化の理由[RPM]

select * from table where status = xx limit 10 offset 100000;

ページングシーンの下では、インデックスがあっても、要求は、スタンドアローンのみ10万例2~3秒程度のデータ量で、非常に遅くなります制限

分析

指数

私たちは、MySQLのインデックスがあることを知っているB +ツリーそれは、バイナリツリーの場合、彼らは木の分布のトップ100の数を知ることができないので、私はバイナリの特性を使用することはできませんので、探しています。B +ツリーにおいて、リーフノードは順に一覧表示することができるO(n)100の多数が、それでもO(n)を見つけるために、複雑さの、またそう遅い他の理由があるかどうかの

、InnoDBののインデックスは2つに分割されている情報へのアクセスによる(著)

  • クラスタ化インデックス:主キーインデックスと対応する実際のデータ、索引リーフ・ノードは、データ・ノード、データを見つけるインデックスを見つけるです
  • セカンダリインデックスは:リーフ・ノードまたは主キーのIDが含まれているインデックス・ノードである2つのノードとして理解することができ、また、あなたは再びデータを照会する必要があります

旧100,000捨てされる場合でも、MySQLのの層化に、MySQLは、セカンダリインデックスの主キーのIDも越えると、クラスタ化インデックスのデータをチェックします、これは自然にゆっくりとハスキーへ100000ランダムIOです

層状

あなたはこの、論理演算子について前の概念を理解する必要があります。論理的なクエリプラン演算子のいくつかを簡単に見て

  • データソース:データソース私たちのSQL文のテーブルです。select name from table1TABLE1
  • 参加:接続を、としてselect * from table1 table2 where table1.name = table2.name、2つのテーブルが参加んです。参加条件は、最も簡単な同等の接続は、もちろん、我々は他の存在を知っているinner joinleft joinright joinなど
  • 選択:選択して、select name from table1 where id = 1フィルタ場所の条件
  • 集計:グループ化、等のselect sum(score) from table1 group by name基による。パケット、重合操作に応じて、いくつかの列は、MAX、MIN、合計、カウントなど、パケット数後に行ってもよい平均
  • Projection:投影,指搜索的列,如select name from table1 where id = 1中的列name
  • Sort:排序,如select * from table1 order by id里面的order by。无序的数据通过这个算子处理后,输出有序的数据
  • Apply:子查询,如select * from (select id,name from table1) as t中的(select id,name from table1) as t。可以进行嵌套查询。

选择、投影、连接就是最基本的算子,其中 Join 有内连接,左外右外连接等多种连接方式

select b from t1, t2 where t1.c = t2.c and t1.a > 5

变成逻辑查询计划之后

  • t1 t2 对应的 DataSource,负责将数据捞上来
  • 上面接个 Join 算子,将两个表的结果按 t1.c = t2.c连接
  • 再按 t1.a > 5 做一个 Selection 过滤
  • 最后将 b 列投影

下图是未经优化的表示,所以说不是mysql不想把limit传递给引擎层,而是因为划分了逻辑算子,所以导致无法直到具体算子包含了多少符合条件的数据

ps:SELECT执行顺序

SQL语句执行顺序 MySQL执行顺序
1 select distinct from
2 from on
3 join join
4 on where
5 where group by
6 group by having+聚合函数
7 having select distinct
8 union union
9 order by order by
10 limit limit

解决方法

解决方法有2种

  • 根据业务实际需求,看能否替换为下一页,上一页的功能,特别在移动端。把limit替换成>id的方式。该id再调用时,需要返回给前端。但是这种有些业务场景不适用
select * from table where status = xx id > 100000 limit 10;
  • 【推荐】嵌套子查询,先查找数据的主键值,因为主键在辅助索引上就有,所以不用回归到聚簇索引的磁盘去拉取。再通过这些已经被limit出来的10个主键id,去查询聚簇索引。这样只会十次随机IO。在业务确实需要用分页的情况下,使用该方案可以大幅度提高性能。通常能满足性能要求
select xxx from in (select id from table where status = xx limit 10 offset 100000);

原文出处,删除作者经历和感想部分,如原作者觉得此文不妥,我会修改

作者:叶不闻
链接:https://juejin.im/post/5c4db295e51d4503834d9c43
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

逻辑算子部分引用了

作者:叁金
链接:http://www.imooc.com/article/278660
来源:慕课网

おすすめ

転載: www.cnblogs.com/n031/p/12014428.html