SQL 优化案例一则

た 入场券 2023-06-05 11:22 127阅读 0赞

导读:

郑松华,知数堂SQL 优化班老师

现任 CCmediaService DBA,主要负责数据库优化相关工作

擅长SQL优化 ,数据核对

想阅读更多内容请点击订阅专栏

640?wx\_fmt=png


大家好,我是知数堂SQL 优化班老师 网名:骑龟的兔子

背景说明:

今天在刷头条的时候,看到下面的文章

https://www.toutiao.com/a6727944177943839243/

看到他的SQL还有优化的空间,经过他的同意写下这篇文章

640?wx\_fmt=png

为了阅读方便,把需要的资料引用到这里。

表结构如下:

  1. CREATE TABLE `statistic_order` (
  2. `oid` bigint(20) NOT NULL,
  3. `o_source` varchar(25) DEFAULT NULL COMMENT '来源编号',
  4. `o_actno` varchar(30) DEFAULT NULL COMMENT '活动编号',
  5. `o_actname` varchar(100) DEFAULT NULL COMMENT '参与活动名称',
  6. `o_n_channel` int(2) DEFAULT NULL COMMENT '商城平台',
  7. `o_clue` varchar(25) DEFAULT NULL COMMENT '线索分类',
  8. `o_star_level` varchar(25) DEFAULT NULL COMMENT '订单星级',
  9. `o_saledep` varchar(30) DEFAULT NULL COMMENT '营销部',
  10. `o_style` varchar(30) DEFAULT NULL COMMENT '车型',
  11. `o_status` int(2) DEFAULT NULL COMMENT '订单状态',
  12. `syctime_day` varchar(15) DEFAULT NULL COMMENT '按天格式化日期',
  13. PRIMARY KEY (`oid`)
  14. ) ENGINE=InnoDB DEFAULT CHARSET=utf8

原文作者优化后的SQL 版本如下:

  1. select S.syctime_day,
  2. sum(case when S.o_source = 'CDE' then 1 else 0 end) as 'CDE',
  3. sum(case when S.o_source = 'SDE' then 1 else 0 end) as 'SDE',
  4. sum(case when S.o_source = 'PDE' then 1 else 0 end) as 'PDE',
  5. sum(case when S.o_source = 'CSE' then 1 else 0 end) as 'CSE',
  6. sum(case when S.o_source = 'SSE' then 1 else 0 end) as 'SSE'
  7. from statistic_order S where S.syctime_day > '2015-05-01' and S.syctime_day < '2016-08-01'
  8. GROUP BY S.syctime_day order by S.syctime_day asc;

执行计划如下图所示:

640?wx\_fmt=jpeg

原文中有如下语言:

在o_source和syctime_day上加上索引之后,效率提高了很多,大概五秒钟就查询出了结果:

原文所示执行计划 :

640?wx\_fmt=jpeg

思路:

从以上条件推测,应该是 o_source 和syctime_day 分别加上单列索引

  1. create index syctimeday_index on statistic_order(syctime_day);
  2. create index osource_index on statistic_order(o_source);

重现了类似执行计划:

  1. root@mysql3306.sock>[test3]>desc select S.syctime_day,
  2. -> sum(case when S.o_source = 'CDE' then 1 else 0 end) as 'CDE',
  3. -> sum(case when S.o_source = 'SDE' then 1 else 0 end) as 'SDE',
  4. -> sum(case when S.o_source = 'PDE' then 1 else 0 end) as 'PDE',
  5. -> sum(case when S.o_source = 'CSE' then 1 else 0 end) as 'CSE',
  6. -> sum(case when S.o_source = 'SSE' then 1 else 0 end) as 'SSE'
  7. -> from statistic_order S where S.syctime_day > '2015-05-01'
  8. -> and S.syctime_day < '2016-08-01'
  9. -> GROUP BY S.syctime_day order by S.syctime_day asc\G
  10. *************************** 1. row ***************************
  11. id: 1
  12. select_type: SIMPLE
  13. table: S
  14. partitions: NULL
  15. type: range
  16. possible_keys: syctimeday_index,osource_index
  17. key: syctimeday_index
  18. key_len: 48
  19. ref: NULL
  20. rows: 1
  21. filtered: 100.00
  22. Extra: Using index condition
  23. 1 row in set, 1 warning (0.00 sec)

优化过程:

下面开始对这个优化开始二次修改:

我们先看下原来的执行计划

640?wx\_fmt=jpeg

我们先看下执行计划,这里type index ,还有key_len 为48

从表结构中有如下字段定义

`syctime_day` varchar(15) DEFAULT NULL

我们定义表结构的时候,最好是,什么数据类型定义什么类型

这里如果是日期类型就应该选用date 类型

因为这样所占用空间就小


















类型  (字节) 范围 格式 用途
DATE 3 1000-01-01/9999-12-31 YYYY-MM-DD 日期值

现在把数据类型更改为date 类型如下 :

  1. CREATE TABLE `statistic_order2` (
  2. `oid` bigint(20) NOT NULL,
  3. `o_source` varchar(25) DEFAULT NULL,
  4. `o_actno` varchar(30) DEFAULT NULL,
  5. `o_actname` varchar(100) DEFAULT NULL,
  6. `o_n_channel` int(2) DEFAULT NULL,
  7. `o_clue` varchar(25) DEFAULT NULL,
  8. `o_star_level` varchar(25) DEFAULT NULL,
  9. `o_saledep` varchar(30) DEFAULT NULL,
  10. `o_style` varchar(30) DEFAULT NULL,
  11. `o_status` int(2) DEFAULT NULL,
  12. `syctime_day` date DEFAULT NULL,
  13. PRIMARY KEY (`oid`),
  14. KEY `syctimeday_index` (`syctime_day`),
  15. KEY `osource_index` (`syctime_day`)
  16. ) ENGINE=InnoDB DEFAULT CHARSET=utf8
  17. root@mysql3306.sock>[test3]>desc select S.syctime_day,
  18. -> sum(case when S.o_source = 'CDE' then 1 else 0 end) as 'CDE',
  19. -> sum(case when S.o_source = 'SDE' then 1 else 0 end) as 'SDE',
  20. -> sum(case when S.o_source = 'PDE' then 1 else 0 end) as 'PDE',
  21. -> sum(case when S.o_source = 'CSE' then 1 else 0 end) as 'CSE',
  22. -> sum(case when S.o_source = 'SSE' then 1 else 0 end) as 'SSE'
  23. -> from statistic_order2 S where S.syctime_day > '2015-05-01' and S.syctime_day < '2016-08-01'
  24. -> GROUP BY S.syctime_day order by S.syctime_day asc\G
  25. *************************** 1. row ***************************
  26. id: 1
  27. select_type: SIMPLE
  28. table: S
  29. partitions: NULL
  30. type: range
  31. possible_keys: syctimeday_index,osource_index
  32. key: syctimeday_index
  33. key_len: 4
  34. ref: NULL
  35. rows: 1
  36. filtered: 100.00
  37. Extra: Using index condition
  38. 1 row in set, 1 warning (0.00 sec)

就会发现 key_len 为 4

还有一个从原来的执行计划的fiter为50可以看出范围太大,就会发生大量的回表操作,也是一个相对负担的操作,那为了优化创建联合索引如下:

  1. create index ix_index on statistic_order2(syctime_day,o_source);

创建之后的执行计划如下:

  1. root@mysql3306.sock>[test3]>desc select S.syctime_day,
  2. -> sum(case when S.o_source = 'CDE' then 1 else 0 end) as 'CDE',
  3. -> sum(case when S.o_source = 'SDE' then 1 else 0 end) as 'SDE',
  4. -> sum(case when S.o_source = 'PDE' then 1 else 0 end) as 'PDE',
  5. -> sum(case when S.o_source = 'CSE' then 1 else 0 end) as 'CSE',
  6. -> sum(case when S.o_source = 'SSE' then 1 else 0 end) as 'SSE'
  7. -> from statistic_order2 S where S.syctime_day+0 > '2015-05-01' and S.syctime_day+0 < '2016-08-01'
  8. -> GROUP BY S.syctime_day order by S.syctime_day asc\G
  9. *************************** 1. row ***************************
  10. id: 1
  11. select_type: SIMPLE
  12. table: S
  13. partitions: NULL
  14. type: index
  15. possible_keys: syctimeday_index,osource_index,ix_index
  16. key: ix_index
  17. key_len: 82
  18. ref: NULL
  19. rows: 1
  20. filtered: 100.00
  21. Extra: Using where; Using index
  22. 1 row in set, 1 warning (0.00 sec)

这样就达到了我所要的最终的优化效果!!

结论:

如果在不更改表结构的情况下,创建ix_index 这个索引,这样也可以达到优化效果。

因为本案例的整体的表的数据量不大,改变列的属性达到的效果差不多,但是随着数据量的增加,差距就会更加明显。

谢谢大家~ 欢迎转发

如有关于SQL优化方面疑问需要交流的,请加入QQ群**(579036588),并@骑兔子的龟 **就可与我联系

END


点击下图小程序订阅

《SQL优化专栏》

get更多优化技能

640?wx\_fmt=png

640?wx\_fmt=png

640?wx\_fmt=gif

扫码加入MySQL技术Q群

(群号:**579036588)**

640?wx\_fmt=jpeg

发表评论

表情:
评论列表 (有 0 条评论,127人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Oracle SQL优化案例研究

    在Oracle SQL的优化中,有许多实际案例可以作为研究对象。这里选取几个典型且具有代表性的案例进行简要分析。 1. **索引选择不合理**:比如在一个经常基于某个字段进行

    相关 一则笑话

    有个牧师开车,在路上见到路旁有个修女,便停车主动载她一程. 修女进车後便翘起脚来,让她可爱的美腿从长袍中露了出来,牧师看了一眼高兴的差点让车子出了意外,在控制车子後,他偷偷