前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >2500W数据量SQL优化过程

2500W数据量SQL优化过程

作者头像
用户5166556
发布2019-11-26 17:28:20
3710
发布2019-11-26 17:28:20
举报
文章被收录于专栏:让技术和时代并行

当Oracle数据库拿到SQL语句时,其会根据查询优化器分析该语句,并根据分析结果生成查询执行计划。也就是说,数据库是执行的查询计划,而不是Sql语句。

先执行From ->Where ->Order By

我们在大多数情况下都知道Where条件添加索引能够提高执行效率,但是对于Order by如何走索引查询?

无排序条件查询(一)

前提条件:2500万数据,如果不添加排序的情况下毫秒内可以完成分页查询:

代码语言:javascript
复制
SELECT *FROM(SELECT B.* ,ROWNUM RNFROM(SELECT  /*+ index(T_AUDITS T_AUDITS_PK) */ c_create_time,c_idFROM T_AUDITS) BWHERE ROWNUM <= 20)WHERE RN > 0;

排序所有字段查询(二)

sql语句:

代码语言:javascript
复制
SELECT *FROM(SELECT B.* ,ROWNUM RNFROM(SELECT  *FROM T_AUDITSORDER BY c_create_time DESC) BWHERE ROWNUM <= 20)WHERE RN > 0;

执行过程:

--------------------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |--------------------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 20 | 16320 | | 2134K (1)| 07:06:56 | | ||* 1 | VIEW | | 20 | 16320 | | 2134K (1)| 07:06:56 | | ||* 2 | COUNT STOPKEY | | | | | | | | || 3 | VIEW | | 26M| 19G| | 2134K (1)| 07:06:56 | | ||* 4 | SORT ORDER BY STOPKEY| | 26M| 8058M| 9233M| 2134K (1)| 07:06:56 | | || 5 | PARTITION RANGE ALL | | 26M| 8058M| | 326K (1)| 01:05:23 |1048575| 1 || 6 | TABLE ACCESS FULL | T_AUDITS | 26M| 8058M| | 326K (1)| 01:05:23 |1048575| 1 |--------------------------------------------------------------------------------------------------------------------------

耗费时间:11秒左右

排序指定字段查询(三)

sql语句:

代码语言:javascript
复制
SELECT *FROM(SELECT B.* ,ROWNUM RNFROM(SELECT  c_create_time, c_idFROM T_AUDITSORDER BY c_create_time DESC) BWHERE ROWNUM <= 20)WHERE RN > 0;

执行过程:

代码语言:javascript
复制
--------------------------------------------------------------------------------------------------------------------------| Id  | Operation                | Name                  | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |--------------------------------------------------------------------------------------------------------------------------|   0 | SELECT STATEMENT         |                       |    20 |  1120 |       |   568K  (1)| 01:53:41 |       |       ||*  1 |  VIEW                    |                       |    20 |  1120 |       |   568K  (1)| 01:53:41 |       |       ||*  2 |   COUNT STOPKEY          |                       |       |       |       |            |          |       |       ||   3 |    VIEW                  |                       |    26M|  1066M|       |   568K  (1)| 01:53:41 |       |       ||*  4 |     SORT ORDER BY STOPKEY|                       |    26M|   867M|  1097M|   568K  (1)| 01:53:41 |       |       ||   5 |      PARTITION RANGE ALL |                       |    26M|   867M|       |   326K  (1)| 01:05:23 |1048575|     1 ||   6 |       TABLE ACCESS FULL  | T_AUDITS |    26M|   867M|       |   326K  (1)| 01:05:23 |1048575|     1 |--------------------------------------------------------------------------------------------------------------------------

耗费时间:4秒左右

由此可以看出sql语句写法不同,查询时间也会有所变化。特别有一点值得注意,查询字段少之后,所占有的排序字节数不一样,1占用19G 2不到1G。由此可以看出在排序的情况下查询字段越大,同时耗费时间越久。

但是对于用户来说4s的时间是不能忍耐的,我们需要继续优化

Bytes The size in bytes of the data the CBO expects each step of the plan to return. This is dependent on the number of rows (Card) and the estimated width of the rows. oracle官方文档

大概意思是指cbo中这一步所处理所有记录的字节数,是估算出来的一组值。

添加索引查询(四)

按照c_create_time添加索引,但是查询过程中还是全表扫描,并没有按照预期走索引。(即使把查询字段id去掉,只查询c_create_time,速度依然不会有所提升)

创建联合索引(排序字段一定要放在之前,否则可能不生效,本人测试如果前后导致比不添加索引速度更慢):

代码语言:javascript
复制
CREATE INDEX T_AUDITS_INDEX1 ON T_AUDITS (C_CREATE_TIME DESC, C_ID DESC);

sql查询语句:

代码语言:javascript
复制
SELECT *FROM(SELECT B.* ,ROWNUM RNFROM(SELECT c_create_time,c_idFROM T_AUDITSORDER BY c_create_time DESC) BWHERE ROWNUM <= 20)WHERE RN > 0;

执行过程(已经走索引):

代码语言:javascript
复制
---------------------------------------------------------------------------------------------------| Id  | Operation          | Name                         | Rows  | Bytes | Cost (%CPU)| Time     |---------------------------------------------------------------------------------------------------|   0 | SELECT STATEMENT   |                              |    20 |  1120 |     4   (0)| 00:00:01 ||*  1 |  VIEW              |                              |    20 |  1120 |     4   (0)| 00:00:01 ||*  2 |   COUNT STOPKEY    |                              |       |       |            |          ||   3 |    VIEW            |                              |    20 |   860 |     4   (0)| 00:00:01 ||   4 |     INDEX FULL SCAN| T_AUDITS_INDEX1 |    26M|   867M|     4   (0)| 00:00:01 |---------------------------------------------------------------------------------------------------

耗费时间:0.01秒

如果说上面查询语句依然不能提高效率,那么可以添加hint强制走索引(在已知内存足够情况下,可以强制放到内存中执行):

代码语言:javascript
复制
SELECT *FROM(SELECT B.* ,ROWNUM RNFROM(SELECT  /*+ index(T_AUDITS T_AUDITS_INDEX!) */ c_create_time,c_idFROM T_AUDITSORDER BY c_create_time DESC) BWHERE ROWNUM <= 20)WHERE RN > 0;

总结(五)

Oracle会话首先在内存中进行排序,如果操作使用内存超过了阈值,Oracle会将操作分为多个较小的操作以使每个可以在内存中操作。部分结果将会被写入磁盘的临时表空间,任何一个会话可以使用的内存数依赖于初始化参数的设置,当排序操作太大以至于不能在内存中执行时,Oracle将在临时表空间中分配空间以执行操作,当然我们也可以有办法强制走内存。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-06-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云原生技术爱好者社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档