我实际上是一次从三个列字段中选择Oracle数据库中的记录。用户可以提供定义的五列中的任何三列。我尝试了下面的两个查询,而Query-1要快得多,第二个问题在这里尽管Query-1有额外的加入。这背后的原因是什么?
查询-1
select y.id,y.form_no, y.ownership, y.issue_date, y.issue_place, y.pin_no,surname, y.given_names, y.date_of_birth_bs
from (
select form_no,
case when lower(place_of_birth) = 'morang' then 1 else 0 end as PlaceOfBirth,
case when date_of_birth_ad = to_date('1985-09-01', 'yyyy-MM-dd') then 1 else 0 end as DateOfBirthAd,
case when issue_date = '20600219' then 1 else 0 end as DateOfIssue,
case when lower(issue_place) = 'morang' then 1 else 0 end as PlaceOfIssue,
case when lower(ownership) = '12005-1746' then 1 else 0 end as ownershipNo
from application
) x, application y
where x.form_no = y.form_no and (x.PlaceOfBirth + x.DateOfBirthAd + x.DateOfIssue + x.PlaceOfIssue + x.ownershipNo) > 2;
查询-2
select id,form_no, ownership, issue_date, issue_place, pin_no,surname, given_names, date_of_birth_bs
from application y
where
(case when lower(place_of_birth) = 'morang' then 1 else 0 end)+
(case when date_of_birth_ad = to_date('1985-09-01', 'yyyy-MM-dd') then 1 else 0 end)+
(case when issue_date = '20600219' then 1 else 0 end)+
(case when lower(issue_place) = 'morang' then 1 else 0 end)+
(case when lower(ownership) = '12005-1746' then 1 else 0 end) > 2;
此外,还有其他方法可以修改查询以使其更快吗?
答案 0 :(得分:1)
对于第二个查询,您可以定义基于函数的索引
create index fidx on application ((case when lower(place_of_birth) = 'morang' then 1 else 0 end)+
(case when date_of_birth_ad = to_date('1985-09-01', 'yyyy-MM-dd') then 1 else 0 end)+
(case when issue_date = '20600219' then 1 else 0 end)+
(case when lower(issue_place) = 'morang' then 1 else 0 end)+
(case when lower(ownership) = '12005-1746' then 1 else 0 end));
获取INDEX RANGE SCAN访问权限。
-------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 40307 | 5117K| 112 (0)| 00:00:02 |
| 1 | TABLE ACCESS BY INDEX ROWID| APPLICATION | 40307 | 5117K| 112 (0)| 00:00:02 |
|* 2 | INDEX RANGE SCAN | FIDX | 7255 | | 19 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
2 - access(CASE LOWER("PLACE_OF_BIRTH") WHEN 'morang' THEN 1 ELSE 0 END +CASE
"DATE_OF_BIRTH_AD" WHEN TO_DATE(' 1985-09-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss')
THEN 1 ELSE 0 END +CASE "ISSUE_DATE" WHEN '20600219' THEN 1 ELSE 0 END +CASE
LOWER("ISSUE_PLACE") WHEN 'morang' THEN 1 ELSE 0 END +CASE LOWER("OWNERSHIP") WHEN
'12005-1746' THEN 1 ELSE 0 END >2)
此方法的问题在于它仅适用于查询中的确切文字值。 如果你可以使用其他参数(例如使用绑定变量),这将无效。
作为替代方案,您可以重写查询添加一些 OR connected 访问谓词并为其添加专用索引。
示例强>
create index fidx1 on application ( lower(place_of_birth) );
create index fidx2 on application ( issue_date );
create index fidx3 on application ( lower(ownership) );
增强查询将是
select id,form_no, ownership, issue_date, issue_place, pin_no,surname, given_names, date_of_birth_bs
from application y
where /*ACCESS */
(lower(place_of_birth) = 'morang' or
issue_date = '20600219' or
lower(ownership) = '12005-1746' ) and
/* FILTER */
((case when lower(place_of_birth) = 'morang' then 1 else 0 end)+
(case when date_of_birth_ad = to_date('1985-09-01', 'yyyy-MM-dd') then 1 else 0 end)+
(case when issue_date = '20600219' then 1 else 0 end)+
(case when lower(issue_place) = 'morang' then 1 else 0 end)+
(case when lower(ownership) = '12005-1746' then 1 else 0 end) > 2);
请注意添加的三个访问谓词
(lower(place_of_birth) = 'morang' or
issue_date = '20600219' or
lower(ownership) = '12005-1746' )
启用INDEX CONCATENATION ACCESS
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 824 | 125K| 1597 (1)| 00:00:20 |
| 1 | CONCATENATION | | | | | |
|* 2 | TABLE ACCESS BY INDEX ROWID| APPLICATION | 411 | 64116 | 798 (1)| 00:00:10 |
|* 3 | INDEX RANGE SCAN | FIDX3 | 3404 | | 3 (0)| 00:00:01 |
|* 4 | TABLE ACCESS BY INDEX ROWID| APPLICATION | 407 | 63492 | 2 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | FIDX1 | 3404 | | 1 (0)| 00:00:01 |
|* 6 | TABLE ACCESS BY INDEX ROWID| APPLICATION | 6 | 936 | 798 (1)| 00:00:10 |
|* 7 | INDEX RANGE SCAN | FIDX2 | 3404 | | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
为什么三个OR连接的谓词?
如果您有五列中的三列匹配,您可以跳过其中两列并将其余三列与OR匹配 - 其中一列必须匹配。
因此,调整查询的一个方法是获取三个最具选择性的列/表达式,并在它们上定义基于索引/函数的索引,并添加访问谓词,如上所示。
提前测试 - 你必须进行三次索引范围扫描并连接结果 - 所以如果索引访问的成本很高(索引访问返回太多记录),你将回到FULL TABLE扫描 (这可能是你当前的访问路径)。