0

我害怕数据库中的奇怪行为,在我的主表UDBMOVEMENT_ORIG(26mil.rows)和UDBIDENTDATA_ORIG(18mil.rows)上创建了满足这些主表的一些默认条件和连接条件的物化视图TMP_MS_UDB_MVUDBMOVEMENT是该对象的同义词)。MV 有大约 1200 万行。我创建了 MV 来查询不太大的对象,MV 得到 3GB,主表总共 12GB。但我不明白即使物理读取和一致获取在 MV 上也比在主表上少,主表上的最终执行时间更短。请参阅下面的我的日志。

为什么?

SQL> set echo on
SQL> @flush
SQL> alter system flush buffer_cache;

System altered.

Elapsed: 00:00:00.20
SQL> alter system flush shared_pool;

System altered.

Elapsed: 00:00:00.65
SQL> SELECT
2 UDBMovement.zIdDevice, UDBMovement.sDevice, UDBMovement.zIdLocal, UDBMovement.sComputer, UDBMovement.tActionTime, UDBIdentData.sCardSubType, UDBIdentData.sCardType, UDBMovement.cEpan, UDBMovement.cText, UDBMovement.lArtRef, UDBMovement.sArtClassRef, UDBMovement.lSequenz, UDBMovement.sTransMark, UDBMovement.lBlock, UDBMovement.sTransType, UDBMovement.lGlobalID, UDBMovement.sFacility, UDBIdentData.sCardClass, UDBMovement.lSingleAmount, UDBMovement.sVAT, UDBMovement.lVATTot, UDBIdentData.tTarifTimeStart, UDBIdentData.tTarifTimeEnd, UDBIdentData.cLicensePlate, UDBIdentData.lMoneyValue, UDBIdentData.lPointValue, UDBIdentData.lTimeValue, UDBIdentData.tProdTime, UDBIdentData.tExpireDate
3 FROM UDBMOVEMENT_orig UDBMovement, Udbidentdata_orig UDBIdentData
4 WHERE
5 UDBMovement.lGlobalId = UDBIdentData.lGlobalRef(+) AND UDBMovement.sComputer = UDBIdentData.sComputer(+)
6 AND UDBMovement.sTransType > 0 AND UDBMovement.sDevice < 1000 AND UDBMovement.sDevice>= 0 AND UDBIdentData.sCardType IN (2) AND (bitand(UDBMovement.sSaleFlag,1) = 0 AND bitand(UDBMovement.sSaleFlag,4) = 0) AND UDBMovement.sArtClassRef < 100
7 AND UDBMovement.tActionTime >= TO_DATE('05/05/2011 00:00:00', 'dd/mm/yyyy hh24:mi:ss') + 0.25 AND UDBMovement.tActionTime < TO_DATE('05/05/2011 00:00:00', 'dd/mm/yyyy hh24:mi:ss') + 0.5
8 ORDER BY tActionTime, lBlock, lSequenz;

4947 rows selected.

Elapsed: 00:00:15.84

Execution Plan
Plan hash value: 1768406139

Id   Operation   Name    Rows    Bytes  TempSpc  Cost (%CPU)     Time

0    SELECT STATEMENT        7166    1238K       20670 (1)   00:04:09
1    SORT ORDER BY       7166    1238K   1480K   20670 (1)   00:04:09
2    NESTED LOOPS                        
3    NESTED LOOPS        7166    1238K       20388 (1)   00:04:05
* 4  TABLE ACCESS BY INDEX ROWID     UDBMOVEMENT_ORIG    7142    809K        7056 (1)    00:01:25
* 5  INDEX RANGE SCAN    IDX_UDBMOVARTICLE   10709           61 (0)  00:00:01
* 6  INDEX UNIQUE SCAN   UDBIDENTDATA_PRIM   1           1 (0)   00:00:01
* 7  TABLE ACCESS BY INDEX ROWID     UDBIDENTDATA_ORIG   1   61      2 (0)   00:00:01


Predicate Information (identified by operation id):

4 - filter("UDBMOVEMENT"."STRANSTYPE">0 AND "UDBMOVEMENT"."SDEVICE"<1000 AND
BITAND("SSALEFLAG",1)=0 AND "UDBMOVEMENT"."SDEVICE">=0 AND BITAND("UDBMOVEMENT"."SSALEFLAG",4)=0)
5 - access("UDBMOVEMENT"."TACTIONTIME">=TO_DATE(' 2011-05-05 06:00:00', 'syyyy-mm-dd
hh24:mi:ss') AND "UDBMOVEMENT"."TACTIONTIME"<TO_DATE(' 2011-05-05 12:00:00', 'syyyy-mm-dd
hh24:mi:ss') AND "UDBMOVEMENT"."SARTCLASSREF"<100)
filter("UDBMOVEMENT"."SARTCLASSREF"<100)
6 - access("UDBMOVEMENT"."LGLOBALID"="UDBIDENTDATA"."LGLOBALREF" AND
"UDBMOVEMENT"."SCOMPUTER"="UDBIDENTDATA"."SCOMPUTER")
7 - filter("UDBIDENTDATA"."SCARDTYPE"=2)
Statistics
543 recursive calls
0 db block gets
84383 consistent gets
4485 physical reads
0 redo size
533990 bytes sent via SQL*Net to client
3953 bytes received via SQL*Net from client
331 SQL*Net roundtrips to/from client
86 sorts (memory)
0 sorts (disk)
4947 rows processed

SQL> @flush
SQL> alter system flush buffer_cache;

System altered.

Elapsed: 00:00:00.12
SQL> alter system flush shared_pool;

System altered.

Elapsed: 00:00:00.74
SQL> SELECT UDBMovement.zIdDevice, UDBMovement.sDevice, UDBMovement.zIdLocal, UDBMovement.sComputer, UDBMovement.tActionTime, UDBMovement.sCardSubType, UDBMovement.sCardType, UDBMovement.cEpan, UDBMovement.cText, UDBMovement.lArtRef, UDBMovement.sArtClassRef, UDBMovement.lSequenz, UDBMovement.sTransMark, UDBMovement.lBlock, UDBMovement.sTransType, UDBMovement.lGlobalID, UDBMovement.sFacility, UDBMovement.sCardClass, UDBMovement.lSingleAmount, UDBMovement.sVAT, UDBMovement.lVATTot, UDBMovement.tTarifTimeStart, UDBMovement.tTarifTimeEnd, UDBMovement.cLicensePlate, UDBMovement.lMoneyValue, UDBMovement.lPointValue, UDBMovement.lTimeValue, UDBMovement.tProdTime
2 FROM UDBMOVEMENT WHERE
3 UDBMovement.sTransType > 0 AND UDBMovement.sDevice < 1000 AND UDBMovement.sDevice>= 0 AND UDBMovement.sCardType IN (2) AND (bitand(UDBMovement.sSaleFlag,1) = 0 AND bitand(UDBMovement.sSaleFlag,4) = 0) AND UDBMovement.sArtClassRef < 100
4 AND UDBMovement.tActionTime >= TO_DATE('05/05/2011 00:00:00', 'dd/mm/yyyy hh24:mi:ss') + 0.25
5 AND UDBMovement.tActionTime < TO_DATE('05/05/2011 00:00:00', 'dd/mm/yyyy hh24:mi:ss') + 0.5 ORDER BY tActionTime, lBlock, lSequenz;

4947 rows selected.

Elapsed: 00:00:26.46

Execution Plan
Plan hash value: 3648898312

Id   Operation   Name    Rows    Bytes   Cost (%CPU)     Time

0    SELECT STATEMENT        2720    443K    2812 (1)    00:00:34
1    SORT ORDER BY       2720    443K    2812 (1)    00:00:34
* 2  MAT_VIEW ACCESS BY INDEX ROWID  TMP_MS_UDB_MV   2720    443K    2811 (1)    00:00:34
* 3  INDEX RANGE SCAN    EEETMP_MS_ACTTIMEDEVICE     2732        89 (0)  00:00:02


Predicate Information (identified by operation id):

2 - filter("UDBMOVEMENT"."STRANSTYPE">0 AND BITAND("UDBMOVEMENT"."SSALEFLAG",4)=0 AND
BITAND("SSALEFLAG",1)=0 AND "UDBMOVEMENT"."SARTCLASSREF"<100)
3 - access("UDBMOVEMENT"."TACTIONTIME">=TO_DATE(' 2011-05-05 06:00:00', 'syyyy-mm-dd
hh24:mi:ss') AND "UDBMOVEMENT"."SDEVICE">=0 AND "UDBMOVEMENT"."SCARDTYPE"=2 AND
"UDBMOVEMENT"."TACTIONTIME"<TO_DATE(' 2011-05-05 12:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
"UDBMOVEMENT"."SDEVICE"<1000)
filter("UDBMOVEMENT"."SCARDTYPE"=2 AND "UDBMOVEMENT"."SDEVICE"<1000 AND
"UDBMOVEMENT"."SDEVICE">=0)
Statistics
449 recursive calls
0 db block gets
6090 consistent gets
2837 physical reads
0 redo size
531987 bytes sent via SQL*Net to client
3953 bytes received via SQL*Net from client
331 SQL*Net roundtrips to/from client
168 sorts (memory)
0 sorts (disk)
4947 rows processed

SQL> spool off

感谢您的回答。

4

2 回答 2

3

我假设所有表/MV 都收集了适当的统计信息。

如果您查看第一个查询的计划,您会看到我们有一个 RANGE SCAN UDBMOVEMENT_ORIG,然后对于通过 where 子句找到的每一行,我们有一个 INDEX UNIQUE SCAN 朝向UDBIDENTDATA_ORIG(可能是它的 PK)。请注意,Oracle 已将您的 OUTER JOIN 转换为标准的 INNER JOIN(嵌套循环)。

第一步返回几行(<10k),因此第二步几乎没有时间。所以我们可以假设第一个查询的大部分工作都花在寻找与 where 子句的条件匹配的行上。数据库选择使用IDX_UDBMOVARTICLE索引。我们缺少它的定义,但TACTIONTIME, SARTCLASSREF由于查询计划,我们可以猜测它覆盖了列 ( )。

第二个查询是直接的RANGE INDEX SCAN,我们再次错过了索引定义,但我们可以再次猜测它涵盖了列 ( TACTIONTIME, SDEVICE, SCARDTYPE, SDEVICE)。


我的结论是您在原始表及其 MV 上没有相同的索引,因此您看到查询时间(苹果和橙子)的差异也就不足为奇了。具有讽刺意味的是,对于这个查询,较小的原始索引比它的对应索引更合适。

我还要指出,数据库非常擅长加入,并且在大多数查询中,您只会看到预加入表的边际收益。有时您甚至可能会看到负收益,因为 MV 将被去规范化,因此更大(因此全扫描成本更高)。

于 2013-02-05T09:52:01.650 回答
0

如果您查看排序统计信息,较慢的查询执行的排序数几乎是较快的查询的两倍:

86 sorts (memory)

对比

168 sorts (memory)

这将在某种程度上解释为什么第二个查询较慢,尽管我怀疑排序本身就是全部原因。时间增加的原因可能与文森特确定的指标不同有关。我怀疑有很多原因加起来会使其整体变慢。

于 2013-02-05T12:34:19.137 回答