假设有两个表...
-----------------
-- contains 10 million rows
create table TST_ITEMEVENT
(
eventId NUMBER(10) not null,
itemId VARCHAR2(20) not null,
line VARCHAR2(10),
type VARCHAR2(20),
timepoint DATE
);
alter table TST_ITEMEVENT add primary key (EVENTID)
create index IDX_ITEMEVENT on TST_ITEMEVENT (line, type, timepoint);
-----------------
-- contains 1000 rows
create table TST_SNAPSHOT
(
snapshotId NUMBER(10) not null,
timeTarget DATE not null
);
…以及它们的两种观点:
CREATE OR REPLACE VIEW tst_SnapshotRelation_V AS
SELECT H.SnapshotId,
H.TimeTarget,
LAG(H.SnapshotId) OVER ( ORDER BY H.TimeTarget) AS PrevSnapshotId
FROM tst_Snapshot H;
CREATE OR REPLACE VIEW tst_ItemAppearance_V AS
SELECT T.SnapshotId,
T.ItemId,
CASE WHEN MAX(T.DateExcluded) >= MAX(T.DateIncluded) THEN 0
WHEN MAX(T.DateIncluded) IS NULL THEN 0
ELSE 1
END AS InStock
FROM (
SELECT
V.SnapshotId AS SnapshotId,
ME.ItemId AS ItemId,
CASE WHEN ME.Line = 'LINE-A' THEN ME.TimePoint END AS DateIncluded,
CASE WHEN ME.Line = 'LINE-B' THEN ME.TimePoint END AS DateExcluded
FROM tst_SnapshotRelation_V V,
tst_ItemEvent ME
WHERE (ME.Line, ME.Type) IN (
('LINE-A', 'Type41'),
('LINE-B', 'Type25')
)
AND ME.TimePoint < V.TimeTarget
) T
GROUP BY T.SnapshotId, T.ItemId;
应该将它们用于类似
的查询中-- "Heavy query"
select *
from tst_SnapshotRelation_V R,
tst_ItemAppearance_V A
where A.SnapshotId = R.PrevSnapshotId
and A.InStock = 1
and R.snapshotid = :X;
此查询的实际基数不大于5000行。
“大量查询”计划:
---------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
---------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4133931 | 421660962 | 1056 | 00:00:13 |
| 1 | MERGE JOIN | | 4133931 | 421660962 | 1056 | 00:00:13 |
| 2 | SORT JOIN | | 4013525 | 232784450 | 1050 | 00:00:13 |
| 3 | VIEW | TST_ITEMAPPEARANCE_V | 4013525 | 232784450 | 1050 | 00:00:13 |
| * 4 | FILTER | | | | | |
| 5 | HASH GROUP BY | | 4013525 | 549852925 | 1050 | 00:00:13 |
| 6 | NESTED LOOPS | | | | | |
| 7 | NESTED LOOPS | | 4013525 | 549852925 | 724 | 00:00:09 |
| 8 | TABLE ACCESS FULL | TST_SNAPSHOT | 103 | 2266 | 3 | 00:00:01 |
| 9 | INLIST ITERATOR | | | | | |
| * 10 | INDEX RANGE SCAN | IDX_ITEMEVENT | 11 | | 3 | 00:00:01 |
| 11 | TABLE ACCESS BY INDEX ROWID | TST_ITEMEVENT | 38966 | 4481090 | 7 | 00:00:01 |
| * 12 | SORT JOIN | | 103 | 4532 | 5 | 00:00:01 |
| * 13 | VIEW | TST_SNAPSHOTRELATION_V | 103 | 4532 | 4 | 00:00:01 |
| 14 | WINDOW SORT | | 103 | 2266 | 4 | 00:00:01 |
| 15 | TABLE ACCESS FULL | TST_SNAPSHOT | 103 | 2266 | 3 | 00:00:01 |
---------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 4 - filter(CASE WHEN MAX(CASE "ME"."LINE" WHEN 'QMHRP' THEN "ME"."TIMEPOINT" END )>=MAX(CASE "ME"."LINE" WHEN 'BM' THEN "ME"."TIMEPOINT" END ) THEN 0 WHEN MAX(CASE "ME"."LINE" WHEN 'BM' THEN
"ME"."TIMEPOINT" END ) IS NULL THEN 0 ELSE 1 END =1)
* 10 - access(("ME"."LINE"='BM' AND "ME"."TYPE"='Entstehung' OR "ME"."LINE"='QMHRP' AND "ME"."TYPE"='Aenderung') AND "ME"."TIMEPOINT"<"H"."TIMETARGET")
* 12 - access("A"."SNAPSHOTID"="R"."PREVSNAPSHOTID")
* 12 - filter("A"."SNAPSHOTID"="R"."PREVSNAPSHOTID")
* 13 - filter("R"."SNAPSHOTID"=TO_NUMBER(:X))
实际上,获得结果(需要至少5分钟)要花一些时间,因为
第一步,执行者从tst_ItemAppearance_V
获取所有行,然后用A.SnapshotId = R.PrevSnapshotId
对其进行过滤。
优化器是否希望对表tst_ItemEvent
使用完全扫描,但是计划中未显示该扫描?
仅当计算出的列R.PrevSnapshotId
用于联接时,此效果才会出现。
例如,当我们使用A.SnapshotId = R.SnapshotId
时-查询会在我的计算机上2秒钟内交付结果。当有过滤器R.PrevSnapshotId = :X
-- "Fast query" example
select *
from tst_SnapshotRelation_V R,
tst_ItemAppearance_V A
where A.SnapshotId = R.PrevSnapshotId
and A.InStock = 1
and R.PrevSnapshotId = :X;
“快速查询”计划:
--------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
--------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4133905 | 421658310 | 52 | 00:00:01 |
| * 1 | HASH JOIN | | 4133905 | 421658310 | 52 | 00:00:01 |
| * 2 | VIEW | TST_SNAPSHOTRELATION_V | 103 | 4532 | 4 | 00:00:01 |
| 3 | WINDOW SORT | | 103 | 2266 | 4 | 00:00:01 |
| 4 | TABLE ACCESS FULL | TST_SNAPSHOT | 103 | 2266 | 3 | 00:00:01 |
| 5 | VIEW | TST_ITEMAPPEARANCE_V | 40135 | 2327830 | 13 | 00:00:01 |
| * 6 | FILTER | | | | | |
| 7 | HASH GROUP BY | | 40135 | 5498495 | 13 | 00:00:01 |
| 8 | NESTED LOOPS | | | | | |
| 9 | NESTED LOOPS | | 40135 | 5498495 | 10 | 00:00:01 |
| * 10 | TABLE ACCESS FULL | TST_SNAPSHOT | 1 | 22 | 3 | 00:00:01 |
| 11 | INLIST ITERATOR | | | | | |
| * 12 | INDEX RANGE SCAN | IDX_ITEMEVENT | 11 | | 3 | 00:00:01 |
| 13 | TABLE ACCESS BY INDEX ROWID | TST_ITEMEVENT | 38966 | 4481090 | 7 | 00:00:01 |
--------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
------------------------------------------
* 1 - access("A"."SNAPSHOTID"="R"."PREVSNAPSHOTID")
* 2 - filter("R"."PREVSNAPSHOTID"=TO_NUMBER(:X))
* 6 - filter(CASE WHEN MAX(CASE "ME"."LINE" WHEN 'LINE-B' THEN "ME"."TIMEPOINT" END )>=
MAX(CASE "ME"."LINE" WHEN 'LINE-A' THEN "ME"."TIMEPOINT" END )
THEN 0
WHEN MAX(CASE "ME"."LINE" WHEN 'LINE-A'
THEN "ME"."TIMEPOINT" END ) IS NULL THEN 0 ELSE 1 END =1)
* 10 - filter("H"."SNAPSHOTID"=TO_NUMBER(:X))
* 12 - access(("ME"."LINE"='LINE-A' AND "ME"."TYPE"='Type14' OR "ME"."LINE"='LINE-B' AND "ME"."TYPE"='Type25') AND "ME"."TIMEPOINT"<"H"."TIMETARGET")
请帮助我了解如何强制优化器使用合理的执行计划。