sql优化案例一—数据分布散导致索引失效走全表扫描

简介: 数据分布太散导致索引失效

问题背景:下午收到慢查询导致超时告警,用pt-query-digest 获取到相应慢sql,如下。
select count(1) from (

        select  mdos.sn_code,count(1) from mps_device_order_static mdos
        inner join business b on b.sid=mdos.sid
        inner join qdsp_device qd on qd.sn_code=mdos.sn_code and b.guid=qd.business_guid
        where 1=1 and mdos.sn_code<>'' and mdos.sn_code<>'null' and  1=1  AND mdos.static_date>='2020-05-01'  AND mdos.static_date<='2020-05-30'
        group by mdos.sn_code) tab;

分析过程:

查看执行计划
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 PRIMARY NULL ALL NULL NULL NULL NULL 58943 100.00 NULL
2 DERIVED mdos NULL ALL idx_static_date,idx_sn_code,idx_sid,idx_static_date_sn_code_total_money_total_count NULL NULL NULL 2064111 28.56 Using where; Using temporary; Using filesort
2 DERIVED qd NULL eq_ref ux_sn_code,ix_business_guid ux_sn_code 202 management.mdos.sn_code 1 100.00 NULL
2 DERIVED b NULL eq_ref PRIMARY,ix_sid_int PRIMARY 144 management.qd.business_guid 1 10.00 Using where

4 rows in set, 1 warning (0.00 sec)

发现驱动表mdos 即mps_device_order_static 走全表扫描

各表索引情况如下:
mps_device_order_static 表索引
PRIMARY KEY (id),
KEY idx_static_date (static_date),
KEY idx_agent_id (agent_id),
KEY idx_sn_code (sn_code),
KEY idx_sid (sid),
KEY idx_static_date_sn_code_total_money_total_count (static_date,sn_code,total_money,total_count)
)

business 表索引

PRIMARY KEY (guid),
UNIQUE KEY ix_account (account),
UNIQUE KEY ix_sid_int (sid),
KEY ix_agent_guid (agent_guid),
KEY ix_open_id (open_id),
KEY ix_vip_guid (vip_guid),
KEY ix_vip_account (vip_account),
KEY ix_vpi_cloud_open_id (vip_cloud_open_id),
KEY ix_sub_channel_number (sub_channel_number),
KEY ix_register_time (register_time) USING BTREE,
KEY ix_wechat_appid (wechat_appid),
KEY idx_tong_cheng_hui_guid (tong_cheng_hui_guid)
)

qdsp_device 表索引
PRIMARY KEY (id),
UNIQUE KEY ux_sn_code (sn_code),
KEY ix_agent_guid (agent_guid),
KEY ix_business_guid (business_guid) USING BTREE,
KEY idx_chain_store_guid_sn_code (chain_store_guid,sn_code),
KEY idx_terminal_number (terminal_number),
KEY idx_storehouse_guid (storehouse_guid),
KEY idx_device_status (device_status)
)

查看了sql各连接条件,和where语句中条件,确认所有条件字段都是有索引的。所以应该是什么原因导致了索引失效

尝试将语句进行拆解,一步一步分析
首先试试驱动表mdos单表执行计划
explain select mdos.sn_code,count(*) from mps_device_order_static mdos

        #inner join business b on b.sid=mdos.sid
        #inner join qdsp_device qd on qd.sn_code=mdos.sn_code and b.guid=qd.business_guid
        where 1=1 and mdos.sn_code<>'' and mdos.sn_code<>'null' AND mdos.static_date>='2020-05-01'  AND mdos.static_date<='2020-05-30'
        group by mdos.sn_code;

+----+-------------+-------+------------+-------+-----------------------------------------------------------------------------+-------------------------------------------------+---------+------+---------+----------+-----------------------------------------------------------+

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE mdos NULL range idx_static_date,idx_sn_code,idx_static_date_sn_code_total_money_total_count idx_static_date_sn_code_total_money_total_count 3 NULL 1032055 50.00 Using where; Using index; Using temporary; Using filesort

1 row in set, 1 warning (0.00 sec)
发现正常走索引

接着试
explain select mdos.sn_code,count(*) from mps_device_order_static mdos

        #inner join business b on b.sid=mdos.sid
        inner join qdsp_device qd on qd.sn_code=mdos.sn_code #and b.guid=qd.business_guid
        where 1=1 and mdos.sn_code<>'' and mdos.sn_code<>'null' AND mdos.static_date>='2020-05-01'  AND mdos.static_date<='2020-05-30'
        group by mdos.sn_code;

+----+-------------+-------+------------+--------+-----------------------------------------------------------------------------+-------------------------------------------------+---------+-------------------------+---------+----------+-----------------------------------------------------------+

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE mdos NULL range idx_static_date,idx_sn_code,idx_static_date_sn_code_total_money_total_count idx_static_date_sn_code_total_money_total_count 3 NULL 1032055 50.00 Using where; Using index; Using temporary; Using filesort
1 SIMPLE qd NULL eq_ref ux_sn_code ux_sn_code 202 management.mdos.sn_code 1 100.00 Using index

也能正常走索引

接着试
explain select mdos.sn_code,count(*) from mps_device_order_static mdos

        inner join business b on b.sid=mdos.sid
        #inner join qdsp_device qd on qd.sn_code=mdos.sn_code and b.guid=qd.business_guid
        where 1=1 and mdos.sn_code<>'' and mdos.sn_code<>'null' AND mdos.static_date>='2020-05-01'  AND mdos.static_date<='2020-05-30'
        group by mdos.sn_code;
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE mdos NULL ALL idx_static_date,idx_sn_code,idx_sid,idx_static_date_sn_code_total_money_total_count NULL NULL NULL 2064111 14.28 Using where; Using temporary; Using filesort
1 SIMPLE b NULL eq_ref ix_sid_int ix_sid_int 4 management.mdos.sid 1 100.00 Using where; Using index

2 rows in set, 1 warning (0.01 sec)
发现走全表索引失效,走全表扫描。这时感觉应该是和business 表关联这里有问题,但还是没找到头绪

改写下sql试试
explain select count(distinct mdos.sn_code) from mps_device_order_static mdos
join business b on b.sid=mdos.sid
join qdsp_device qd on qd.sn_code=mdos.sn_code and b.guid=qd.business_guid
where 1=1 and mdos.sn_code<>'' AND mdos.static_date>='2020-05-01' AND mdos.static_date<='2020-05-30';

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE mdos NULL ALL idx_static_date,idx_sn_code,idx_sid,idx_static_date_sn_code_total_money_total_count NULL NULL NULL 2064111 14.28 Using where
1 SIMPLE qd NULL eq_ref ux_sn_code ux_sn_code 202 management.mdos.sn_code 1 100.00 Using index
1 SIMPLE b NULL eq_ref ix_sid_int ix_sid_int 4 management.mdos.sid 1 100.00 Using where; Using index

3 rows in set, 1 warning (0.00 sec)
还是不行

接着试试走强制索引
explain select count(distinct mdos.sn_code) from mps_device_order_static mdos force index(idx_static_date)
join business b on b.sid=mdos.sid
join qdsp_device qd on qd.sn_code=mdos.sn_code and b.guid=qd.business_guid
where 1=1 and mdos.sn_code<>'' AND mdos.static_date>='2020-05-01' AND mdos.static_date<='2020-05-30';

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE mdos NULL range idx_static_date idx_static_date 3 NULL 589440 90.00 Using index condition; Using where
1 SIMPLE qd NULL eq_ref ux_sn_code,ix_business_guid ux_sn_code 202 management.mdos.sn_code 1 100.00 NULL
1 SIMPLE b NULL eq_ref PRIMARY,ix_sid_int PRIMARY 144 management.qd.business_guid 1 10.00 Using where

3 rows in set, 1 warning (0.00 sec)
这时发现能走索引,速度快了很多。但是没找到原因

后来咨询了一位大佬,根据他的猜测可能是表数据量比较大,同时数据分布比较分散,所以导致索引失效走全表扫描。根据他的猜测,缩短了过滤时间,将mdos.static_date>='2020-05-01' AND mdos.static_date<='2020-05-30' 缩短到一周试试。
explain select count(distinct mdos.sn_code) from mps_device_order_static mdos force index(idx_static_date)
join business b on b.sid=mdos.sid
join qdsp_device qd on qd.sn_code=mdos.sn_code and b.guid=qd.business_guid
where 1=1 and mdos.sn_code<>'' AND mdos.static_date>='2020-05-01' AND mdos.static_date<='2020-05-07';

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE mdos NULL range idx_static_date idx_static_date 3 NULL 133714 90.00 Using index condition; Using where
1 SIMPLE qd NULL eq_ref ux_sn_code,ix_business_guid ux_sn_code 202 management.mdos.sn_code 1 100.00 NULL
1 SIMPLE b NULL eq_ref PRIMARY,ix_sid_int PRIMARY 144 management.qd.business_guid 1 10.00 Using where

3 rows in set, 1 warning (0.01 sec)
可以正常走索引了。

至此,得出两种解决办法
1、利用force index 强制走索引
select count(distinct mdos.sn_code) from mps_device_order_static mdos force index(idx_static_date)
join business b on b.sid=mdos.sid
join qdsp_device qd on qd.sn_code=mdos.sn_code and b.guid=qd.business_guid
where 1=1 and mdos.sn_code<>'' AND mdos.static_date>='2020-05-01' AND mdos.static_date<='2020-05-30';

2、缩短过滤时间,查询多次
select count(distinct mdos.sn_code) from mps_device_order_static mdos force index(idx_static_date)
join business b on b.sid=mdos.sid
join qdsp_device qd on qd.sn_code=mdos.sn_code and b.guid=qd.business_guid
where 1=1 and mdos.sn_code<>'' AND mdos.static_date>='2020-05-01' AND mdos.static_date<='2020-05-07';

第2种方法更好,更快

目录
相关文章
|
25天前
|
SQL 存储 关系型数据库
一文搞懂SQL优化——如何高效添加数据
**SQL优化关键点:** 1. **批量插入**提高效率,一次性建议不超过500条。 2. **手动事务**减少开销,多条插入语句用一个事务。 3. **主键顺序插入**避免页分裂,提升性能。 4. **使用`LOAD DATA INFILE`**大批量导入快速。 5. **避免主键乱序**,减少不必要的磁盘操作。 6. **选择合适主键类型**,避免UUID或长主键导致的性能问题。 7. **避免主键修改**,保持索引稳定。 这些技巧能优化数据库操作,提升系统性能。
221 4
一文搞懂SQL优化——如何高效添加数据
|
1月前
|
SQL 存储 数据库
sql事务、视图和索引
sql事务、视图和索引
14 0
|
1月前
|
SQL 存储 数据库连接
日活3kw下,如何应对实际业务场景中SQL过慢的优化挑战?
在面试中,SQL调优是一个常见的问题,通过这个问题可以考察应聘者对于提升SQL性能的理解和掌握程度。通常来说,SQL调优需要按照以下步骤展开。
|
1月前
|
SQL 存储 弹性计算
GaussDB SQL调优:建立合适的索引
GaussDB SQL调优:建立合适的索引
12 0
|
1月前
|
存储 关系型数据库 MySQL
最全MySQL面试60题(含答案):存储引擎+数据库锁+索引+SQL优化等
最全MySQL面试60题(含答案):存储引擎+数据库锁+索引+SQL优化等
174 0
|
3天前
|
SQL 分布式计算 资源调度
一文解析 ODPS SQL 任务优化方法原理
本文重点尝试从ODPS SQL的逻辑执行计划和Logview中的执行计划出发,分析日常数据研发过程中各种优化方法背后的原理,覆盖了部分调优方法的分析,从知道怎么优化,到为什么这样优化,以及还能怎样优化。
|
6天前
|
SQL 自然语言处理 数据库
NL2SQL实践系列(2):2024最新模型实战效果(Chat2DB-GLM、书生·浦语2、InternLM2-SQL等)以及工业级案例教学
NL2SQL实践系列(2):2024最新模型实战效果(Chat2DB-GLM、书生·浦语2、InternLM2-SQL等)以及工业级案例教学
NL2SQL实践系列(2):2024最新模型实战效果(Chat2DB-GLM、书生·浦语2、InternLM2-SQL等)以及工业级案例教学
|
10天前
|
SQL 关系型数据库 数据库
【后端面经】【数据库与MySQL】SQL优化:如何发现SQL中的问题?
【4月更文挑战第12天】数据库优化涉及硬件升级、操作系统调整、服务器/引擎优化和SQL优化。SQL优化目标是减少磁盘IO和内存/CPU消耗。`EXPLAIN`命令用于检查SQL执行计划,关注`type`、`possible_keys`、`key`、`rows`和`filtered`字段。设计索引时考虑外键、频繁出现在`where`、`order by`和关联查询中的列,以及区分度高的列。大数据表改结构需谨慎,可能需要停机、低峰期变更或新建表。面试中应准备SQL优化案例,如覆盖索引、优化`order by`、`count`和索引提示。优化分页查询时避免大偏移量,可利用上一批的最大ID进行限制。
37 3
|
14天前
|
SQL 存储 数据挖掘
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
服务器数据恢复环境: 一台安装windows server操作系统的服务器。一组由8块硬盘组建的RAID5,划分LUN供这台服务器使用。 在windows服务器内装有SqlServer数据库。存储空间LUN划分了两个逻辑分区。 服务器故障&初检: 由于未知原因,Sql Server数据库文件丢失,丢失数据涉及到3个库,表的数量有3000左右。数据库文件丢失原因还没有查清楚,也不能确定数据存储位置。 数据库文件丢失后服务器仍处于开机状态,所幸没有大量数据写入。 将raid5中所有磁盘编号后取出,经过硬件工程师检测,没有发现明显的硬件故障。以只读方式将所有磁盘进行扇区级的全盘镜像,镜像完成后将所
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
|
16天前
|
SQL 数据库 索引
SQL索引失效原因分析与解决方案
SQL索引失效原因分析与解决方案
22 0