【问题标题】:Oracle simple Select query optimizationOracle 简单选择查询优化
【发布时间】:2013-07-31 20:19:00
【问题描述】:

我有以下简单的动态选择查询

Select RELATIONSHIP 
  from DIME_MASTER 
 WHERE CIN=? AND SSN=? AND ACCOUNT_NUMBER=?

该表有 1,083,701 条记录。此查询需要 11 到 12 秒才能执行,这很昂贵。 DIME_MASTER 表有 ACCOUNT、CARD_NUMBER INDEXES。请帮助我优化此查询,以使查询执行时间低于秒。

【问题讨论】:

  • 好吧,在cinssnaccount_number 的所有三个上放置一个索引,按选择性顺序排列(列中唯一值最多的应该是第一个)。如果可能,使索引唯一...然后动态是可怕的...我假设您的意思是您更改变量而不是每次都构建查询。
  • 好吧,如果没有适当的索引,难怪这会很慢...您尝试了什么?执行计划显示什么?
  • 您需要向我们展示表和索引定义,以及每个表的行数。也许您的表格定义不佳。也许索引没有正确创建。也许您认为您在该列上没有索引。没有看到表和索引定义,我们无法判断。我们还需要行计数,因为这会极大地影响查询优化。如果您知道如何进行EXPLAIN 或获得执行计划,请将结果也放入问题中。
  • 当结果列表的总数很高时,查询将需要一些时间来执行。所以确保给定的约束是否给出了这么多的结果。
  • @Ben 如果您对所有列都具有相等条件,则索引中列的顺序无关紧要。它是 O(log n)。

标签: oracle select optimization


【解决方案1】:

查看谓词信息:

--------------------------------------
 1 - filter(TO_NUMBER("DIME_MASTER"."SSN")=226550956 
            AND TO_NUMBER("DIME_MASTER"."ACCOUNT_NUMBER")=4425050005218650 
            AND TO_NUMBER("DIME_MASTER"."CIN")=00335093464) 

列的类型是 NVARCHAR,但查询中的参数是 NUMBER。
Oracle 必须将数字转换为字符串,但有时它在转换时不是很聪明。
预言家和算命先生并不总是正确的 ;)

这些强制转换会阻止查询使用索引。

使用显式转换将查询重写为:

Select RELATIONSHIP 
  from DIME_MASTER 
 WHERE CIN=to_char(?) AND SSN=to_char(?) AND ACCOUNT_NUMBER=to_char(?)

然后运行这个命令:

exec dbms_stats.gather_table_stats( user, 'DIME_MASTER' );

并运行查询并向我们展示新的解释计划。

请不要在此处粘贴解释计划,它们不可读,
请改用pastebin,并在此处仅粘贴链接,谢谢。

看看这个简单的例子,它说明了为什么需要显式转换:

CREATE TABLE "DIME_MASTER" ( 
  "ACCOUNT_NUMBER" NVARCHAR2(16)
);
insert into dime_master
select round( dbms_random.value( 1, 100000 )) from dual
connect by level <= 100000;
commit;
create index dime_master_acc_ix on dime_master( account_number );

explain plan for select * from dime_master
where account_number = 123;

select * from table( dbms_xplan.display );

Plan hash value: 1551952897

---------------------------------------------------------------------------------
| Id  | Operation         | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |             |     3 |    54 |    70   (3)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| DIME_MASTER |     3 |    54 |    70   (3)| 00:00:01 |
---------------------------------------------------------------------------------

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

   1 - filter(TO_NUMBER("ACCOUNT_NUMBER")=123)




explain plan for select * from dime_master
where account_number = to_char( 123 );

select * from table( dbms_xplan.display );
Plan hash value: 3367829596

---------------------------------------------------------------------------------------
| Id  | Operation        | Name               | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |                    |     3 |    54 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| DIME_MASTER_ACC_IX |     3 |    54 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------

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

   1 - access("ACCOUNT_NUMBER"=U'123')

【讨论】:

  • 抱歉,回复晚了,在看到您的回复之前,我发现 oracle 正在执行 to_char 编号的相同操作,因此没有使用所需的索引并花费更多时间来执行查询。我修改了我的查询,如下所示:
  • 从 DIME_MASTER WHERE CIN= 中选择关系?和社会安全号码=? AND ACCOUNT_NUMBER=?和 CIN 像 '?%' 和 SSN 像 '?%' 和 ACCOUNT_NUMBER LIKE '?%' 并且它开始使用索引和查询很快。
【解决方案2】:

根据列的基数(总行数/唯一值) - 您可以在每列上创建位图索引。位图索引对于and / or 操作非常有用。

根据经验,位图索引对于大于 10% 的基数很有用。

create bitmap index DIME_MASTER_CIN_BIX on DIME_MASTER (CIN);

【讨论】:

  • 我如何在查询中使用它?
  • 我为 CIN 和 SSN create bitmap index DIME_MASTER_CIN_BIX on DIME_MASTER (CIN); create bitmap index DIME_MASTER_SSN_BIX on DIME_MASTER (SSN); 创建了 2 个位图索引,但性能没有任何改善。查询仍然需要 11.3 到 11.5 秒。
  • DIME_MASTER 结构CREATE TABLE "DIME"."DIME_MASTER" ( "ACCOUNT_NUMBER" NVARCHAR2(16), "APPLICATION_NUMBER" NVARCHAR2(14), "FIRST_NAME" NVARCHAR2(15), "LAST_NAME" NVARCHAR2(25), "SSN" NVARCHAR2(9), "CIN" NVARCHAR2(12), "DATE_UPDATED" DATE, "BOOK_INDICATOR" NVARCHAR2(1), "CARD_NUMBER" NVARCHAR2(16), "RELATIONSHIP" NVARCHAR2(1) )
  • ------------------------------------------ --------------------------- |身份证 |操作 |姓名 |行 |字节 |成本 | | 0 |选择声明 | | 1 | 79 |第2365章|* 1 |表访问完全 | DIME_MASTER | 1 | 79 |第2365章谓词信息(由操作 id 标识): -------------------------------------- 1 - 过滤器(TO_NUMBER("DIME_MASTER"."SSN")=226550956 AND TO_NUMBER("DIME_MASTER"."ACCOUNT_NUMBER")=4425050005218650 AND TO_NUMBER("DIME_MASTER"."CIN")=00335093464) 注意:cpu costing 已关闭
  • 从上面解释计划看起来索引根本没有被使用,oracle 正在进行全表扫描。我尝试使用如下提示,但执行计划仍然显示全表扫描select /*+ index(DIME_MASTER (DIME_MASTER_CIN_BIX)) */ * from DIME_MASTER where CIN=00335093464
猜你喜欢
  • 2016-04-13
  • 1970-01-01
  • 2019-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-11
  • 2014-07-06
相关资源
最近更新 更多