[英]why index defined in the table not being used by the query optimizer? (mysql)
[英]Index is not being used by optimizer
我有一个查询,由于对表进行全面扫描而导致性能非常差。我检查了统计信息以重建索引,但它不起作用。
SQL语句:
select distinct NA_DIR_EMAIL d, NA_DIR_EMAIL r
from gcr_items , gcr_deals
where gcr_deals.GCR_DEALS_ID=gcr_items.GCR_DEALS_ID
and
gcr_deals.bu_id=:P0_BU_ID
and
decode(:P55_DIRECT,'ALL','Y',trim(upper(NA_ORG_OWNER_EMAIL)))=
decode(:P55_DIRECT,'ALL','Y',trim(upper(:P55_DIRECT)))
order by 1
Execution Plan :
Plan hash value: 3180018891
-------------------------------------------------------------------------
| Id | Operation | Name | Rows | Time |
-------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 8 | 00:11:42 |
| 1 | SORT ORDER BY | | 8 | 00:11:42 |
| 2 | HASH UNIQUE | | 8 | 00:11:42 |
|* 3 | HASH JOIN | | 7385 | 00:11:42 |
|* 4 | VIEW | index$_join$_002 | 10462 | 00:00:05 |
|* 5 | HASH JOIN | | | |
|* 6 | INDEX RANGE SCAN | GCR_DEALS_IDX12 | 10462 | 00:00:01 |
| 7 | INDEX FAST FULL SCAN| GCR_DEALS_IDX1 | 10462 | 00:00:06 |
|* 8 | TABLE ACCESS FULL | GCR_ITEMS | 7386 | 00:11:37 |
-------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("GCR_DEALS"."GCR_DEALS_ID"="GCR_ITEMS"."GCR_DEALS_ID")
4 - filter("GCR_DEALS"."BU_ID"=TO_NUMBER(:P0_BU_ID))
5 - access(ROWID=ROWID)
6 - access("GCR_DEALS"."BU_ID"=TO_NUMBER(:P0_BU_ID))
8 - filter(DECODE(:P55_DIRECT,'ALL','Y',TRIM(UPPER("NA_ORG_OWNER_EMAI
L")))=DECODE(:P55_DIRECT,'ALL','Y',TRIM(UPPER(:P55_DIRECT))))
首先,必须在不使用decode
功能的情况下将WHERE子句中的条件的一部分分解(或“反编译”或“重新复仇”)成更简单的形式,查询优化器可以理解这种形式:
AND
decode(:P55_DIRECT,'ALL','Y',trim(upper(NA_ORG_OWNER_EMAIL)))=
decode(:P55_DIRECT,'ALL','Y',trim(upper(:P55_DIRECT)))
变成:
AND (
:P55_DIRECT = 'ALL'
OR
trim(upper(:P55_DIRECT)) = trimm(upper(NA_ORG_OWNER_EMAIL))
)
为了根据索引中存储的值在表中查找行,Oracle使用一种名为Index scan的访问方法,有关详细信息,请参见此链接:
https://docs.oracle.com/cd/B19306_01/server.102/b14211/optimops.htm#i52300
最常见的访问方法之一是“ 索引范围扫描”,请参见此处:
https://docs.oracle.com/cd/B19306_01/server.102/b14211/optimops.htm#i45075
该文档说(在后一个链接中):
当发现条件中指定的索引的一个或多个前导列时,优化器将使用范围扫描,例如:
col1 =:b1
col1 <:b1
col1>:b1
索引中前导列的前述条件的AND组合
像'ASD%'这样的col1通配符搜索不应处于领先位置,否则像'%ASD'这样的条件col1不会导致范围扫描。
上面的意思是说,优化程序只能使用索引来查找包含基本比较运算符的查询条件的行: = < > <= >= LIKE
,用于将简单值与纯列名称进行比较 。
文档没有明确说出-您需要推断出它们在行与行之间的读数-这是一个事实,即在条件中使用某些函数时,形式为function( column_name )
或function( expression_involving_column_names )
,然后是索引范围无法使用扫描 。
在这种情况下,查询优化器必须为表中的每一行分别评估该表达式,因此必须读取所有行(执行全表扫描)。
一个简短的结论和经验法则:
WHERE子句中的函数可能会阻止优化器使用索引
如果您在WHERE子句中看到某个功能,则表明您正在运行红灯
立即停止并思考此函数如何影响查询优化器和查询性能的三倍,然后尝试将条件重写为优化器能够理解的形式。
现在看一下我们重写的条件:
AND (
:P55_DIRECT = 'ALL'
OR
trim(upper(:P55_DIRECT)) = trimm(upper(NA_ORG_OWNER_EMAIL))
)
和STOP -仍有两个函数trim
和upper
施加到名为NA_ORG_OWNER_EMAIL柱。 我们需要考虑它们如何影响查询优化器。
我假设您在单列上创建了一个普通索引:
CREATE INDEX somename ON GCR_ITEMS( NA_ORG_OWNER_EMAIL )
。
如果是,则索引仅包含NA_ORG_OWNER_EMAIL的纯值。
但是查询正在尝试查找trimm(upper(NA_ORG_OWNER_EMAIL))
值,这些值未存储在索引中,因此在这种情况下不能使用此索引。
这种情况需要基于函数的索引 :
https://docs.oracle.com/cd/E11882_01/appdev.112/e41502/adfns_indexes.htm#ADFNS00505
CREATE INDEX somename ON GCR_ITEMS( trim( upper( NA_ORG_OWNER_EMAIL )))
不幸的是,即使基于函数的索引仍然无法解决问题,因为查询中的条件过于笼统-如果值:P55_DIRECT = ALL,则查询必须从表中检索所有行(执行全表扫描),否则必须使用索引以在其中搜索值。
这是因为查询优化器在第一次执行时仅计划了一次查询(将其视为“已编译”)。 然后,该计划将存储在缓存中,并用于对所有进一步执行执行查询。 该参数的值事先未知,因此该计划必须考虑每种可能的情况,因此将始终执行全表扫描。
在12c中,有一个新功能“自适应查询优化”:
https://docs.oracle.com/database/121/TGSQL/tgsql_optcncpt.htm#TGSQL94982
查询优化器在其中分析每次运行时查询的每个参数,并能够检测出该计划对于某些运行时参数不是最佳选择,并根据实际参数的值选择更好的“子计划” ...但是您必须使用12c ,并另外为企业版付费,因为只有该版本包含该功能。 在这种情况下,仍然不确定自适应计划是否会奏效。
您无需付费即可使用12c EE的方法是将此常规查询分为两个单独的变体,一个用于:P55_DIRECT = ALL的情况,另一个用于其余情况,然后根据需要在客户端(您的应用程序)中运行适当的变体根据此参数的值。
:P55_DIRECT = ALL的版本,将执行全表扫描
where gcr_deals.GCR_DEALS_ID=gcr_items.GCR_DEALS_ID
and
gcr_deals.bu_id=:P0_BU_ID
order by 1
以及用于其他情况的版本,该版本将使用基于函数的索引:
where gcr_deals.GCR_DEALS_ID=gcr_items.GCR_DEALS_ID
and
gcr_deals.bu_id=:P0_BU_ID
and
trim(upper(:P55_DIRECT)) = trimm(upper(NA_ORG_OWNER_EMAIL))
order by 1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.