![]() |
|
U别: 初
Alexander Kuznetsov , 芝加哥,伊利诺斯?br />
2002 q?8 ?01 ?/p>
有时候,物理数据库结构中的一ơ简单更改会引h注目地改q查询性能。除了烦引外QDB2 UDB qؓ您提供了ȝ表(实例化的查询表)Q在许多情况下,q些表比索引更有效。本文将提供一些示例来演示使用ȝ表的优点?/blockquote>有时候,物理数据库结构中的一ơ简单更改会显著地改q查询性能。除了烦引外QDB2] Universal Database?qؓ您提供实例化的查询表Q在版本 7.2 和更早的发行版中Q称为“ȝ表”)Q在许多情况下,q些表比索引更有效。其实,实例化的查询表(materialized query tableQMQTQ是Ҏ查询l果定义的表。本文将描述一些示例,在这些示例中Q与单独使用索引相比QMQT 提供更有效的性能改进?
![]()
![]()
![]()
![]()
回页?/font>
MQT 可以帮助您避免对于每ơ查询重复计(?SUMQ。让我们假设有一个名?CUSTOMER_ORDER 的表Q它存储了好几年的客戯单。该表的记录过一百万条,q_行宽?400 个字节。现在,假设我们必须?2001 q的订单q行多次查询Qƈ且我们只需要表中的三列Q如下所C:
select SUM(AMOUNT), trans_dt from db2inst2.CUSTOMER_ORDER where trans_dt between '1/1/2001' and '12/31/2001' group by trans_dt
?/p>
select SUM(AMOUNT), status from db2inst2.CUSTOMER_ORDER where trans_dt between '1/1/2001' and '12/31/2001' group by status
如果有适当的烦引,那么q些查询被作为烦引扫描来执行?清单 1是执行计划的摘录Q它表明使用索引扫描q行查询的预计成本是 152455?
清单 1. ?CUSTOMER_ORDER 表运行查询的成本
-------------------- SECTION --------------------------------------- Section = 1 SQL Statement: select SUM(AMOUNT), trans_dt from db2inst2.CUSTOMER_ORDER where trans_dt between '1/1/2001' and '12/31/2001' group by trans_dt Estimated Cost = 152455 Estimated Cardinality = 378 Q这里省略了一些行Q? Subsection #2: Access Table Name = DB2INST2.CUSTOMER_ORDER ID = 2,591 | #Columns = 1 | Index Scan: Name = DB2INST2.CUST_ORD_TRANS_DT ID = 4 | | Index Columns: | | | 1: TRANS_DT (Ascending) Q这里省略了一些行Q? End of section
现在Q让我们创徏一?MQTQ它包含我们所需的列和行Q包括d计算?/p>
CREATE TABLE DB2INST2.SUMMARY_CUSTOMER_ORDER_2001 AS (SELECT SUM(AMOUNT) AS TOTAL_SUM, TRANS_DT, STATUS FROM DB2INST2.CUSTOMER_ORDER WHERE TRANS_DT BETWEEN '1/1/2001' AND '12/31/2001' GROUP BY TRANS_DT, STATUS) DATA INITIALLY DEFERRED REFRESH DEFERRED;
子句
DATA INITIALLY DEFERRED
表示Q数据不作ؓ CREATE TABLE 语句的一部分插入到表中。而是您必L?REFRESH TABLE 语句来填充表。子?REFRESH DEFERRED
表示Q表中的数据仅作为发?REFRESH TABLE 语句时的快照反映查询l果。有兛_?MQT 的更多信息,请参?SQL Reference?当我们准备填充刚才创建的 MQT Ӟ发出下面的语句:
REFRESH TABLE DB2INST2.SUMMARY_CUSTOMER_ORDER_2001;
现在Q对 MQT 的查询速度快很多,因ؓ MQT 的大相当小Q它的行很短Q与?400 个字节相比,它才 45 个字节)?清单 2 昄了由 dynexpln 生成的执行计划的摘录Q它表明了一个显著的性能改进Q与上一个计划的预计成本 152455 相比Q它只有 101?
-------------------- SECTION --------------------------------------- Section = 1 SQL Statement: select sum(total_sum), trans_dt from db2inst2.summary_customer_order_2001 where trans_dt between '1/1/2001' and '12/31/2001' group by trans_dt Estimated Cost = 101 Estimated Cardinality = 25 q里省略了一些行 Subsection #1: Access Summary Table Name = DB2INST2.SUMMARY_CUSTOMER_ORDER_2001 ID = 2,44 | #Columns = 2 | Relation Scan Q这里省略了一些行Q? | | Sortheap Allocation Parameters: | | | #Rows = 21 | | | Row Width = 45 | | Piped Q这里省略了一些行Q?
注:如果 2001 q?CUSTOMER_ORDER 中的数据在刷C后又q行了更斎ͼ则需要再ơ刷?MQT?/p>
![]()
![]()
![]()
![]()
回页?/font>
让我们假设,我们l常需要最新的 2002 q总计。过d 2002 q?1 ?3 日运行得非常快的报告Q在 5 月就q行得慢多了Q因?2002 q的数据量增加了。正如我们前面所描述的那P查询?CUSTOMER_ORDER 表上作ؓ索引扫描执行?
现在Q我们应该考虑 MQT 能如何帮助我们改q性能。然而,因ؓ数据始终在更新而且我们需要最新数据,所以不能?REFRESH DEFERREDQ因Z一ơ更新基表时QMQT 不与基表同步。现在,让我们用 REFRESH IMMEDIATE ?ENABLE QUERY OPTIMIZATION 选项来创?MQT?/p>
CREATE TABLE DB2INST2.SUMMARY_CUSTOMER_ORDER_2002 AS( SELECT TRANS_DT, STATUS, COUNT(*) AS COUNT_ALL, SUM(AMOUNT) AS SUM_AMOUNT, COUNT(AMOUNT) AS COUNT_AMOUNT FROM DB2INST2.CUSTOMER_ORDER GROUP BY TRANS_DT, STATUS) DATA INITIALLY DEFERRED REFRESH IMMEDIATE ENABLE QUERY OPTIMIZATION;
REFRESH IMMEDIATE
表示Q在?REFRESH TABLE 语句填充 MQT 后,MQT 的内容始l是最新的?重要事项Q?/b>Z使优化器能够自动选择 MQTQENABLE QUERY OPTIMIZATION 必须是有效的Q这是缺省|?
其它语法说明Q?/b>所有聚合都出现?SELECT 列表的末。另外,虽然我们的业务只x SUM(AMOUNT)Q但我们仍必d COUNT(*) ?COUNT(AMOUNT) 包括在全查询中。原因很ҎC。让我们假设正在从基表中删除一个给定日期的所有记录:
DELETE FROM DB2INST2.CUSTOMER_ORDER WHERE TRANS_DT = ?/1/2002?
现在QDB2 必须到特定日期的所有记录都已消失ƈ删除 MQT 中的所有相应记录。有?COUNT 字段可以 DB2 快速执行它Q而不必扫描表或其索引。仅?AMOUNT 列可I时Q才需?COUNT(AMOUNT)?/p>
现在Q该填充 MQT q刷新其l计信息了:
REFRESH TABLE DB2INST2.SUMMARY_CUSTOMER_ORDER_2002; RUNSTATS ON TABLE DB2INST2.SUMMARY_CUSTOMER_ORDER_2002 WITH DISTRIBUTION;
现在Q让我们看一下查询性能是如何改q的QEstimated Cost = 392Q?清单 3是查询执行计划的摘录Q?
-------------------- SECTION --------------------------------------- Section = 1 SQL Statement: select SUM(AMOUNT), trans_dt from db2inst2.customer_order where trans_dt >= '1/1/2002' group by trans_dt Estimated Cost = 392 Estimated Cardinality = 268 Q这里省略了一些行Q? Subsection #1: Access Summary Table Name = DB2INST2.SUMMARY_CUSTOMER_ORDER_2002 ID = 2,46 | #Columns = 2 | Relation Scan
注:?CUSTOMER_ORDERQ不是ȝ表)是在查询中指定的。优化器已经自动选择使用 MQT?/p>
无论何时修改 CUSTOMER_ORDER 表,互斥的表锁就会在 SUMMARY_CUSTOMER_ORDER_2002 上保留,直到事务l束为止。只有同时具有聚合函数和 REFRESH IMMEDIATE 选项?MQT 才会q样。因此,修改 CUSTOMER_ORDER 中相兛_D(包括所有插入和删除Q的事务必须很短Q以减少锁争用。这个问题不适用于用 REFRESH DEFERRED 选项创徏?MQTQ也不适用于复制的 MQTQ在下一节中描述Q?
![]()
![]()
![]()
![]()
回页?/font>
让我们假讑֜分区环境中有一个名?CUSTOMER_DATA 的大表。该?CUSTOMER_DATA 与它的子表ƈ|(CollocateQ。分区键是系l生成的整数 CUSTOMER_ID。表 CUSTOMER_DATA 有一个对另一个表 ZIP_CODE 的引用。表 CUSTOMER_DATA ?ZIP_CODE 未被q置。然而,q两个表常常q接在一赗让我们研究一?清单 4中所C的讉K计划?
清单 4. ?ZIP_CODE 的连接会引v跨节点广?/a>
-------------------- SECTION --------------------------------------- Section = 1 SQL Statement: select c.*, z.zip, z.state_name, z.country_name from db2inst2.customer_address c join db2inst2.zip_code z on c.zip_cd = z.zip_cd Estimated Cost = 100975 Estimated Cardinality = 255819 Coordinator Subsection: Distribute Subsection #2 | Broadcast to Node List | | Nodes = 0, 1 Distribute Subsection #1 | Broadcast to Node List | | Nodes = 0, 1 Access Table Queue ID = q1 #Columns = 38 Return Data to Application | #Columns = 38 Subsection #1: Access Table Queue ID = q2 #Columns = 4 | Output Sorted | | #Key Columns = 1 | | | Key 1: (Ascending) Nested Loop Join | Access Table Name = DB2INST2.CUSTOMER_ADDRESS ID = 2,591 | | #Columns = 35 | | Index Scan: Name = DB2INST2.CU_ZIP_CD ID = 2 | | | Index Columns: | | | | 1: ZIP_CD (Ascending) | | | #Key Columns = 1 | | | | Start Key: Inclusive Value | | | | | 1: ? | | | | Stop Key: Inclusive Value | | | | | 1: ? | | | Data Prefetch: Eligible 162 | | | Index Prefetch: Eligible 162 | | Lock Intents | | | Table: Intent Share | | | Row : Next Key Share | | Insert Into Asynchronous Table Queue ID = q1 | | | Broadcast to Coordinator Node | | | Rows Can Overflow to Temporary Table Insert Into Asynchronous Table Queue Completion ID = q1 Subsection #2: Access Table Name = DB2INST2.ZIP_CODE ID = 2,590 | #Columns = 4 | Relation Scan | | Prefetch: Eligible | Lock Intents | | Table: Intent Share | | Row : Next Key Share | Insert Into Sorted Temp Table ID = t1 | | #Columns = 4 | | #Sort Key Columns = 1 | | | Key 1: ZIP_CD (Ascending) | | Sortheap Allocation Parameters: | | | #Rows = 4479 | | | Row Width = 36 | | Piped Sorted Temp Table Completion ID = t1 Access Temp Table ID = t1 | #Columns = 4 | Relation Scan | | Prefetch: Eligible | Insert Into Asynchronous Table Queue ID = q2 | | Broadcast to All Nodes of Subsection 1 | | Rows Can Overflow to Temporary Table Insert Into Asynchronous Table Queue Completion ID = q2 End of section
ZIP_CODE 表不会经常更斎ͼ因ؓ不常有新的邮政编码)Q但会经常成接目标。每ơ发出导致连接的查询Ӟ必须?ZIP_CODE 表广播到每个节点?/p>
q对于要使用 复制?/i> MQT 来说Q可能是个好情况Q它Z可能已经在单个分点组中创建的表,但您需要在节点l中的所有数据库分区中进行复Ӟ以便启用频繁讉K的数据的q置。要创徏复制?MQTQ调用带 REPLICATED 关键字的 CREATE TABLE 语句?
CREATE TABLE DB2INST2.SUMMARY_ZIP_CODE AS (SELECT * FROM DB2INST2.ZIP_CODE) DATA INITIALLY DEFERRED REFRESH IMMEDIATE ENABLE QUERY OPTIMIZATION REPLICATED;
定义中不允许有聚合。ZIP_CODE 表在 ZIP_CD 上有唯一的烦引。让我们填充该表Q在其上创徏索引q更新统计信息:
REFRESH TABLE DB2INST2.SUMMARY_ZIP_CODE; CREATE INDEX AAA_TTT ON DB2INST2.SUMMARY_ZIP_CODE(ZIP_CD); RUNSTATS ON TABLE DB2INST2.SUMMARY_ZIP_CODE WITH DISTRIBUTION AND DETAILED INDEXES ALL;
现在Q优化器自动选择使用复制的表Q这P每次q行查询Ӟ不必?ZIP_CODE 表广播到每个节点?/p>
清单 5. 通过使用复制?ZIP_CODE 表,避免某些跨节点广?/a>
-------------------- SECTION --------------------------------------- Section = 1 SQL Statement: select c.*, z.zip, z.state_name, z.country_name from db2inst2.customer_address c join db2inst2.zip_code z on c.zip_cd = z.zip_cd Estimated Cost = 101171 Estimated Cardinality = 255819 Coordinator Subsection: Distribute Subsection #1 | Broadcast to Node List | | Nodes = 0, 1 Access Table Queue ID = q1 #Columns = 38 Return Data to Application | #Columns = 38 Subsection #1: Access Summary Table Name = DB2INST2.SUMMARY_ZIP_CODE ID = 2,47 | #Columns = 4 | Relation Scan | | Prefetch: Eligible | Lock Intents | | Table: Intent Share | | Row : Next Key Share | Insert Into Sorted Temp Table ID = t1 | | #Columns = 4 | | #Sort Key Columns = 1 | | | Key 1: ZIP_CD (Ascending) | | Sortheap Allocation Parameters: | | | #Rows = 8958 | | | Row Width = 36 | | Piped Sorted Temp Table Completion ID = t1 Access Temp Table ID = t1 | #Columns = 4 | Relation Scan | | Prefetch: Eligible Nested Loop Join | Access Table Name = DB2INST2.CUSTOMER_ADDRESS ID = 2,591 | | #Columns = 35 | | Index Scan: Name = DB2INST2.CU_ZIP_CD ID = 2 | | | Index Columns: | | | | 1: ZIP_CD (Ascending) | | | #Key Columns = 1 | | | | Start Key: Inclusive Value | | | | | 1: ? | | | | Stop Key: Inclusive Value | | | | | 1: ? | | | Data Prefetch: Eligible 162 | | | Index Prefetch: Eligible 162 | | Lock Intents | | | Table: Intent Share | | | Row : Next Key Share | | Insert Into Asynchronous Table Queue ID = q1 | | | Broadcast to Coordinator Node | | | Rows Can Overflow to Temporary Table Insert Into Asynchronous Table Queue Completion ID = q1 End of section
虽然在我们的CZ中,使用复制?MQT 的预计成本稍微高了点Q?01171 vs. 100975Q(因ؓ我们正在另外一U空闲系l上q行Q这U系l将两个分区攑一台计机上。)然而,当节炚w留在不同计算Zq且它们之间的网l很忙时Q在q种情况下用复制的 MQT 的性能优点会变得明显?/p>
所以,当您从以下这L表中复制数据Ӟ使用复制?MQT 会有性能斚w的优势:
- 是经常连接的?
- 很少更新Q即使曾l更新过Q?
- 不太大(虽然如果q置的性能优势可以抉|复制的一ơ性成本,您可能会考虑复制不太更新的大表。)
另外Q对于复制的 MQTQ不会发生针?REFRESH IMMEDIATE 表所描述的锁定问题?
![]()
![]()
![]()
![]()
回页?/font>
REFRESH IMMEDIATE vs. REFRESH DEFERRED
REFRESH IMMEDIATE MQT 会象索引那样影响查询的性能。这些媄响包括:
- 加速相关选择QselectQ语句的性能?
- 只要有意义,q优化器自动选择它们?
- 会降低插入(insertQ、更斎ͼupdateQ和删除QdeleteQ语句的性能?
- 不能直接更新?
- 可能会占用相当大的磁盘空间?
- 在更新其期间Q可能会保留互斥锁?
要查看对更新性能的媄响,请参?清单 6Q仍没有 MQTQ中所C的 INSERT 语句?EXPLAIN 输出?
清单 6. 对基?ZIP_CODE 表执行的 INSERT 操作
-------------------- SECTION --------------------------------------- Section = 1 SQL Statement: insert into db2inst2.zip_code(zip_cd, zip, state_cd, state_name, country_name) values (60606, '60606', 'IL', 'Illinois', 'United States') Estimated Cost = 25 Estimated Cardinality = 1 Q这里省略了一些行Q?
现在Q让我们d?REFRESH IMMEDIATE 选项创徏?MQTQƈ查看 清单 7 中所C的 EXPLAIN 输出?
清单 7. ?REFRESH IMMEDIATE 创徏?MQT 上的 INSERT 会增加性能成本
-------------------- SECTION --------------------------------------- Section = 1 SQL Statement: insert into db2inst2.zip_code(zip_cd, zip, state_cd, state_name, country_name) values (60606, '60606', 'IL', 'Illinois', 'United States') Estimated Cost = 50 Estimated Cardinality = 1 Q这里省略了一些行Q?
在这个特D示例中Q当存在 REFRESH IMMEDIATE MQT Ӟ插入记录的预计成本是双倍的。另一斚wQREFRESH DEFERRED MQT 没有降低插入、更新和删除语句的性能?/p>
适度使用 REFRESH IMMEDIATE MQTQ以仅仅优化频繁q行且当前数据很重要的查询。一?MQT 不适于立即h条g。可以在 SQL Reference中找到准的规则?
![]()
![]()
![]()
![]()
回页?/font>
优化器可以根据以下条仉用?REFRESH IMMEDIATE 选项创徏?MQT 来代替其Q?/p>
- 、MQT 及其索引的当前统计信息?
- CURRENT QUERY OPTIMIZATION 讄的倹{?
如果 CURRENT REFRESH AGE 讄选项讄?ANYQ则优化器可以用用 REFRESH DEFERRED 选项创徏?MQT。在 SQL Reference中详l描qC CURRENT QUERY OPTIMIZATION ?CURRENT REFRESH AGE 讄选项?
Z化器提供 MQT、创建适当的烦引ƈ使统计信息保持最新。ƈ让优化器选择是用基表还是用ȝ表。在某些情况下,优化器将选择不?MQT?/p>
不管 CURRENT REFRESH AGE ?CURRENT QUERY OPTIMIZATION 讄选项的值是什么,您都可以直接?SELECT 语句?WHERE 子句中用 REFRESH DEFERRED ?REFRESH IMMEDIATE 来指?MQT?/p>
![]()
![]()
![]()
![]()
回页?/font>
正如我们所看到的那P如果正确应用?MQTQ那么它们在各种情况下会非常有用。上面的CZ演示了如何应?MQT 来改q查询性能。虽?MQT 使用h十分方便Q但需要额外的盘I间。用 REFRESH DEFERRED 选项创徏?MQT 不会影响对基表执行插入、更新和删除的性能Q而用 REFRESH IMMEDIATE 选项创徏?MQT 会媄响?
![]()
![]()
![]()
![]()
回页?/font>
![]()
![]()
![]()
![]()
回页?/font>
![]()
![]()
![]()
Alexander Kuznetsov 在Y件设计、开发和数据库管理方面已l有十四q的l验。目前,他正在设?DB2 UDB EEE 中多 TB U群集数据库。Alexander ?IBM 认证的高U技术专ӞDB2 集Q和 IBM 认证的解x案专Ӟ数据库管理和应用E序开发)。可以通过 comp.databases.ibm-db2 新闻l与他联pR?
]]>