`
renzhelife
  • 浏览: 669923 次
文章分类
社区版块
存档分类
最新评论

SQL优化-COUNT_ INDEX的巧用

 
阅读更多

一个SQL COUNT 优化案例,作一个小结

SQL需求:在一个8000W的表中,找出修改时间为某一时间段的记录,并且某字段不为空:
select count(*)
from aliim.udb_user_profile a
where a.gmt_modified >= to_date('2008-07-21 14:29:38', 'yyyy-mm-dd hh24:mi:ss')
and a.gmt_modified <= to_date('2008-07-21 15:34:50', 'yyyy-mm-dd hh24:mi:ss')
and a.AEP_USER_ID is not null

首先想到的是在 gmt_modified 字段中创建单列索引,让查询走索引,并返回到表中过滤 a.AEP_USER_ID is not null.

create index udb_user_profile_gmtm_ind on udb_user_profile(gmt_modified ) online compute statistics ;

在测试库,看执行计划:

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------

-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 75 | 6 |
| 1 | SORT AGGREGATE | | 1 | 75 | |
|* 2 | TABLE ACCESS BY INDEX ROWID| UDB_USER_PROFILE | 481 | 36075 | 6 |
|* 3 | INDEX RANGE SCAN | UDB_USER_PROFILE_GMTM_IND | 17308 | | 2 |
-------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - filter("A"."AEP_USER_ID" IS NOT NULL)
3 - access("A"."GMT_MODIFIED">=TO_DATE('2008-07-20 14:29:38', 'yyyy-mm-dd hh24:mi:ss')
AND "A"."GMT_MODIFIED"<=TO_DATE('2008-07-21 15:34:50', 'yyyy-mm-dd hh24:mi:ss'))


Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
27 consistent gets
18 physical reads
0 redo size
379 bytes sent via SQL*Net to client
500 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

结果比较理想,但到了产品库中,相同的执行计划,却发现这条SQL执行了40多分钟.......
原因是因为生产库中所能选择到的数据远比测试库要多得多(10W以上).
我们作了分析:
oracle先走索引:UDB_USER_PROFILE_GMTM_IND ,找到满足条件的ROWID后(如果是100000条,至少是300个块),那么下一步就去表中找到这100000条记录(最坏的情况是这100000记录都分散在不同的块,那么这一次的读将会是100000个),最后作filter("A"."AEP_USER_ID" IS NOT NULL)并返回实际满足条件的COUNT值。

初想这个执行计划没有啥大问题,而且也走得似乎很合情合理,但就是时间太长了,,,,,

下面是高手出马的结果:

从 GMT_MODIFIED 列来看,我们没有更好的办法来优化,那么我们来看一下AEP_USER_ID这个列中有没有文章可做:

我们来看一下AEP_USER_ID的数据分布:
-----------------
NOT NULL : 5000000
NULL : 75000000

我们知道,ORACLE的索引是不存储为NULL的数据的,因为NOTNULL的数据比较少,所以索引也相对比较小。 如果让COUNT不访问表而直接访问索引,那将会是一个比较理想的路径,于是就大胆的作了测试:

create index udb_user_profile_auid_ind on udb_user_profile(AEP_USER_ID) online compute statistics;

再将SQL改成如下形式:
select /*+ordered use_hash(a b) index_ffs(b UDB_USER_PROFILE_AUID_IND)*/
count(*)
from aliim.udb_user_profile a, aliim.udb_user_profile b
where a.rowid = b.rowid
and a.gmt_modified >=
to_date('2008-07-20 14:29:38', 'yyyy-mm-dd hh24:mi:ss')
and a.gmt_modified <=
to_date('2008-07-21 15:34:50', 'yyyy-mm-dd hh24:mi:ss')
and b.AEP_USER_ID is not null

看执行计划:
-------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 22 | 7 |
| 1 | SORT AGGREGATE | | 1 | 22 | |
|* 2 | HASH JOIN | | 1 | 22 | 7 |
|* 3 | INDEX RANGE SCAN | UDB_USER_PROFILE_GMTM_IND | 2 | 28 | 4 | (直接走index即可)
|* 4 | INDEX FAST FULL SCAN| UDB_USER_PROFILE_AUID_IND | 1 | 8 | 2 |
-------------------------------------------------------------------------------------

oracle只走了两个索引,将对两个索引作了HASH连接,没有回表。
当完全配置后,运行这个SQL只用了不到1分钟的时间。

优化过程中,主要原理还是让ORACLE去访问更少的数据块。

当然这种方法还是有一定的风险:
当b.AEP_USER_ID 的非空值越来越大时,那么访问UDB_USER_PROFILE_AUID_IND这个索引的时间也会越来越长,到时候这个SQL的执行计划是不是还有那么优越,就要视情况而定了!

最后,这确实是一种优化的好思路!

分享到:
评论

相关推荐

    ORACLE SQL性能优化系列

    在缺省情况下,ORACLE采用CHOOSE优化器, 为了避免那些不必要的全表扫描(full table scan) , 你必须尽量避免使用CHOOSE优化器,而直接采用基于规则或者基于成本的优化器. 2. 访问Table的方式 ORACLE 采用两种...

    微软内部资料-SQL性能优化5

    In a nonclustered index, the leaf level contains each index key, plus a bookmark that tells SQL Server where to find the data row corresponding to the key in the index. A bookmark can take one of two ...

    微软内部资料-SQL性能优化3

    Index An entire index of a table. Table An entire table, including all data and indexes. Extent A contiguous group of data pages or index pages. Page An 8-KB data page or index page. Key Row lock ...

    SQLServer2008查询性能优化 2/2

    书名: SQLServer2008查询性能优化 作者: 弗里奇(Grant Fritchey) 出版社: 人民邮电出版社 出版日期: 2010年8月1日 ISBN: 9787115230294 编辑推荐 《SQL Server 2008查询性能优化》为你提供了处理查询性能所...

    微软内部资料-SQL性能优化2

    Before we look at how SQL Server uses and manages its memory, we need to ensure a full understanding of the more common memory related terms. The following definitions will help you understand how SQL...

    SQLServer2008查询性能优化 1/2

    书名: SQLServer2008查询性能优化 作者: 弗里奇(Grant Fritchey) 出版社: 人民邮电出版社 出版日期: 2010年8月1日 ISBN: 9787115230294 编辑推荐 《SQL Server 2008查询性能优化》为你提供了处理查询性能所...

    SQL sever 实训

    --使用IF UPDATE(column)尽可能优化上题的触发器,以提高系统效率 ALTER TRIGGER UPDATE_ProNo_Stocks_TRIGGER ON Product FOR UPDATE AS IF UPDATE (ProNo) PRINT '已更新' GO --单元十三 游标 --创建存储过程...

    SQL21日自学通

    第17 天使用SQL 来生成SQL 语句351 目标351 使用SQL 来生成SQL 语句的目的351 几个SQL*PLUS 命令352 SET ECHO ON/OFF353 SET FEEDBACK ON/OFF353 SET HEADING ON/OFF 353 SPOOL FILENAME/OFF353 START FILENAME354 ...

    让Oracle跑得更快 Oracle 10g性能分析与优化思路.part2.rar

    12.2.2 db_file_multiblock_read_count 328 12.2.3 pga_aggregate_target和sga_target 334 12.2.4 optimizer_dynamic_sampling 334 第13章 性能报告 335 13.1 awr性能报告 335 13.1.1 生成awr性能报告 337 13.1.2 ...

    SQL培训第一期

    1 SQL基础 1.1 基本概念 结构化查询语言(Structured Query Language)简称SQL,是一种关系数据库查询语言,用于存取数据以及查询、更新和管理关系数据库系统。 1.2 语句结构 1.2.1 数据查询语言(DQL) 对数据库进行...

    让Oracle跑得更快 Oracle 10g性能分析与优化思路.part1.rar

    12.2.2 db_file_multiblock_read_count 328 12.2.3 pga_aggregate_target和sga_target 334 12.2.4 optimizer_dynamic_sampling 334 第13章 性能报告 335 13.1 awr性能报告 335 13.1.1 生成awr性能报告 337 13.1.2 ...

    ORACLE9i_优化设计与系统调整

    §6.2.9 步骤9:优化资源争用 89 §6.2.10 步骤10:优化所采用的平台 89 §6.3 应用优化方法 90 §6.3.1 设定明确的优化目标 90 §6.3.2 创建最少可重复测试 90 §6.3.3 测试假想 90 §6.3.4 记录和自动测试 90 §...

    Oracle SQL高级编程(资深Oracle专家力作,OakTable团队推荐)--随书源代码

    10.2 SQL优化 257 10.2.1 测试执行计划 257 10.2.2 跨多个执行的测试 260 10.2.3 测试查询改变的影响 263 10.2.4 寻找其他优化机会 266 10.2.5 将子查询因子化应用到PL/SQL中 270 10.3 递归子查询 273 ...

    SQL语句教程.pdf

    ♦ 进阶 SQL: 介绍 SQL 进阶概念,以及如何用 SQL 来执行一些较复杂的运算。 ♦ SQL 语法: 这一页列出所有在这个教材中被提到的 SQL 语法。 对于每一个指令, 我们将会先列出及解释这个指令的语法, 然后用一个例子...

    关于mysql中innodb的count优化问题分享

    一般采用二级索引去count:比如:id ...但是如果用secondary index 代码如下:select count(*) from table where aid&gt;=0; 则会快很多。 为什么用 secondary index 扫描反而比 primary key 扫描来的要快呢?这就需要了解inn

    Oracle9i的init.ora参数中文说明

    ), interpreted (然后 PL/SQL 模块将被编译为 PL/SQL 字节代码格式), debug (PL/SQL 模块将用探测调试符号来编译), non_debug。 默认值: " interpreted, non_debug " plsql_native_linker: 说明: 此参数指定链接...

    最全的oracle常用命令大全.txt

    SQL&gt;select index_name,index_type,table_name from user_indexes order by table_name; 查看索引被索引的字段 SQL&gt;select * from user_ind_columns where index_name=upper('&index_name'); 查看索引的大小 ...

    Oracle8i_9i数据库基础

    §1.10 使用SQL Worksheet工作 46 第二章 查询基础 50 §2.1 SELECT语句 50 §2.2 SQL中的单记录函数 50 §2.2.1 单记录字符函数 50 §2.2.2 单记录数字函数 56 §2.2.3 单记录日期函数 62 §2.2.4 单记录转换函数 ...

Global site tag (gtag.js) - Google Analytics