MySQL为啥有时候会选错索引
发布时间:2022-01-18 13:57:07 所属栏目:MySql教程 来源:互联网
导读:本篇内容介绍了MySQL为什么有时候会选错索引的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! 今天在生产环境中看到一个慢SQL,是个核心业务表,数据13
本篇内容介绍了“MySQL为什么有时候会选错索引”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! 今天在生产环境中看到一个慢SQL,是个核心业务表,数据1300万+ 看一下表索引: mysql>show index from `order` +-----------------+----------------------+--------------------+------------------------+-----------------------+---------------------+-----------------------+--------------------+------------------+----------------+----------------------+-------------------+-------------------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +-----------------+----------------------+--------------------+------------------------+-----------------------+---------------------+-----------------------+--------------------+------------------+----------------+----------------------+-------------------+-------------------------+ | order | 0 | PRIMARY | 1 | id | A | 10493505 | | | | BTREE | | | | order | 0 | uidx_order | 1 | order_seq | A | 10512924 | | | | BTREE | | | | order | 1 | idx_user | 1 | user_id | A | 1995181 | | | YES | BTREE | | | | order | 1 | idx_shop | 1 | shop_id | A | 53933 | | | YES | BTREE | | | | order | 1 | idx_out_channel | 1 | out_channel | A | 524 | | | YES | BTREE | | | | order | 1 | idx_out_channel | 2 | out_order_no | A | 10512924 | | | YES | BTREE | | | | order | 1 | idx_order_time | 1 | order_time | A | 9867734 | | | | BTREE | | | | order | 1 | idx_update_time | 1 | update_time | A | 8305698 | | | | BTREE | | | | order | 1 | idx_create_time | 1 | create_time | A | 9951390 | | | | BTREE | | | +-----------------+----------------------+--------------------+------------------------+-----------------------+---------------------+-----------------------+--------------------+------------------+----------------+----------------------+-------------------+-------------------------+ 返回行数:[9],耗时:4 ms. mysql>SELECT id,order_seq,user_id FROM `ORDER` WHERE delete_flag = 0 AND user_id = 'd4b0c318b28a46968718dddbaf4775c0' AND display_status = 2 ORDER BY order_time asc LIMIT 0,20 +--------------+---------------------+----------------------------------+ | id | order_seq | user_id | +--------------+---------------------+----------------------------------+ | 6068129 | 20161128183300861 | d4b0c318b28a46968718dddbaf4775c0 | | 6118611 | 20161206171509550 | d4b0c318b28a46968718dddbaf4775c0 | | 6885081 | 20170427104933189 | d4b0c318b28a46968718dddbaf4775c0 | | 7720299 | 2017101718252243 | d4b0c318b28a46968718dddbaf4775c0 | | 10319613 | 201905281103186182 | d4b0c318b28a46968718dddbaf4775c0 | | 505498 | 2019082116584284235 | d4b0c318b28a46968718dddbaf4775c0 | | 10840144 | 1119082315041792571 | d4b0c318b28a46968718dddbaf4775c0 | +--------------+---------------------+----------------------------------+ 返回行数:[7],耗时:18534 ms. 耗时18s,这个查询速度肯定是不能接受的。 我们看一下执行计划: mysql>EXPLAIN SELECT id,order_seq,user_id FROM `ORDER` WHERE delete_flag = 0 AND user_id = 'd4b0c318b28a46968718dddbaf4775c0' AND display_status = 2 ORDER BY order_time asc LIMIT 0,20 +--------------+-----------------------+-----------------+----------------------+----------------+-------------------------+----------------+-------------------+---------------+----------------+--------------------+-----------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +--------------+-----------------------+-----------------+----------------------+----------------+-------------------------+----------------+-------------------+---------------+----------------+--------------------+-----------------+ | 1 | SIMPLE | ORDER | | index | idx_user | idx_order_time | 5 | | 2705 | 0.01 | Using where | +--------------+-----------------------+-----------------+----------------------+----------------+-------------------------+----------------+-------------------+---------------+----------------+--------------------+-----------------+ 执行计划中看到,这个SQL走索引idx_order_time,根据经验判断,此索引效率很差。而扫描行数为2705,慢日志显示扫描行数为13,347,074,二者相差甚远,那么为什么会出现如此大的差异呢? 选择索引是优化器的工作。而优化器选择索引的目的,是找一个最优的执行方案,并用最小的代价去执行语句。在数据库里面,扫描行数是影响执行代价的因素之一。扫描的行数越少,意味着访问磁盘数据的次数越少,消耗的CPU资源越少。 当然,扫描行数并不是唯一的判断标准,优化器还会结合是否使用临时表,是否排序等因素进行综合判断。扫描行数是怎么判断的? MySQL在真正执行SQL之前,并不能准确的判断满足这个条件的数据有多少行,只能按统计信息来估算行数。 索引的统计信息就是索引的“区分度”,一个索引不同的值越多,这个索引的区分度就越好,而一个索引上不同的值的个数,我们称之为“基数”,基数越大,索引的区分度越好。 (编辑:武汉站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |