表 | 列 | PK/FK | 目標表(列) |
DATE_DIM | DATE_ID | PK | 無 |
PRODUCT_DIM | PRODUCT_ID | PK | 無 |
STORE_DIM | STORE_ID | PK | 無 |
SALES_FACT | DATE_ID | FK | DATE_DIM (DATE_ID) |
SALES_FACT | PRODUCT_ID | FK | PRODUCT_DIM (PRODUCT_ID) |
SALES_FACT | STORE_ID | FK | STORE_DIM (STORE_ID) |
db2 -tvf alter_sales_fact.txt -z alter_sales_fact.log
清單 24.alter_sales_fact.txt 文件的內容CONNECT TO DSS_DB;
ALTER TABLE SKAPOOR.SALES_FACT ADD CONSTRAINT DATE_DIM_FK FOREIGN KEY
(DATE_ID) REFERENCES DATE_DIM;
ALTER TABLE SKAPOOR.SALES_FACT ADD CONSTRAINT STORE_DIM_FK FOREIGN KEY
(STORE_ID) REFERENCES STORE_DIM;
ALTER TABLE SKAPOOR.SALES_FACT ADD CONSTRAINT PRODUCT_DIM_FK FOREIGN KEY
(PRODUCT_ID) REFERENCES PRODUCT_DIM;
CREATE INDEX SKAPOOR.IND_DATE_STORE ON SKAPOOR.SALES_FACT (DATE_ID, STORE_ID);
CONNECT RESET;
步驟 1B:收集關于所有表的統計信息: 優化器根據統計信息適當地計算備選查詢執行計劃(QEP)的成本,并選擇最佳計劃。在繼續下一步驟之前,我們需要收集一些統計信息。 清單 25. 收集關于所有表的統計信息db2 -tvf runstats.ddl -z runstats.log
清單 26. runstats.ddl 的內容CONNECT TO DSS_DB;
RUNSTATS ON TABLE SKAPOOR.DATE_DIM WITH DISTRIBUTION AND INDEXES ALL;
RUNSTATS ON TABLE SKAPOOR.STORE_DIM WITH DISTRIBUTION AND INDEXES ALL;
RUNSTATS ON TABLE SKAPOOR.PRODUCT_DIM WITH DISTRIBUTION AND INDEXES ALL;
RUNSTATS ON TABLE SKAPOOR.SALES_FACT WITH DISTRIBUTION AND INDEXES ALL;
CONNECT RESET;
創建了外鍵之后,可以看看 DB2 優化器如何利用參照完整性來消除連接。 步驟 1C:解釋查詢: 清單 27. 含無損連接的查詢SELECT
D.MONTH AS MONTH,
S.STORE_ID AS STORE_ID,
S.DISTRICT AS DISTRICT,
S.REGION AS REGION,
SUM(F1.QUANTITY * F1.PRICE) AS AMOUNT
FROM
SKAPOOR.SALES_FACT F1,
SKAPOOR.DATE_DIM D,
SKAPOOR.PRODUCT_DIM P,
SKAPOOR.STORE_DIM S
WHERE
F1.DATE_ID=D.DATE_ID AND
F1.PRODUCT_ID=P.PRODUCT_ID AND
F1.STORE_ID=S.STORE_ID AND
F1.DATE_ID BETWEEN '2006-01-01' AND '2006-01-31' AND
F1.STORE_ID IN (29, 30, 42, 55, 67, 72, 82, 99, 123, 199) AND
D.MONTH = 1
GROUP BY
S.STORE_ID,S.DISTRICT,S.REGION,D.MONTH)
下面顯示了解釋此查詢的方法之一:db2 connect to dss_db
db2 set current explain mode explain
db2 -tvf JOIN_ELIM_QUERY.SQL -z JOIN_ELIM_QUERY.log
db2 set current explain mode no
db2 connect reset
其中 JOIN_ELIM_QUERY.SQL 的內容只包括 清單 27 中的查詢,以分號結尾。 可以使用 db2exfmt 工具查看查詢執行計劃:db2exfmt -d dss_db -g TIC -w -1 -n % -s % -# 0 -o join_elim.txt
輸出在 join_elim.txt 中。要獲得關于 db2exfmt 工具的具體信息,可以使用 -h 選項。 請打開 下載 小節中的 JOIN_ELIM 文件,看看查詢優化器生成的一個訪問計劃,其中與 PRODUCT_DIM 的連接已經被消除。 可以查看 db2exfmt 輸出中的 "Optimized Statement" 部分,注重 PRODUCT_DIM 表已從查詢中移除。 注重:使用外鍵之類的參照約束時,插入、刪除和更新操作可能無法正常執行。假如性能對于這些操作來說非常要害,但是連接排除優化在查詢中也比較有用,那么可以將外鍵約束定義為純信息型(informational) 的。這個方法后面的練習就是針對這一選項的。 步驟 1D:解釋和運行整個查詢。 為了解釋查詢,采用與步驟 1C 中相同的步驟:db2 connect to dss_db
db2 set current explain mode explain
db2 -tvf QUERY1.SQL -z QUERY1.log
db2 set current explain mode no
db2 connect reset
其中,QUERY1.SQL 的內容只包括 清單 2 中的查詢,以分號結尾。 可以使用 db2exfmt 工具查看查詢執行計劃:db2exfmt -d dss_db -g TIC -w -1 -n % -s % -# 0 -o test1.txt
查詢執行計劃應該類似于 下載 小節中的 Test 1 所提供的查詢執行計劃。 為了運行查詢,要使用 db2batch 工具來評測性能。在此之前,應該讓 db2 實例經過一個再循環過程,以便對每種方法進行公平比較,避免其它因素影響性能(例如,后面測試的方法可能受益于之前留下的緩沖池,從而歪曲了評測結果)。 注重:在運行這些測試時,我們的測試系統是空閑的,沒有其他活動在運行。 使用 db2stop force 停止 db2,再使用 db2start 重新啟動它。使用 db2batch 獲得所用時間的信息,如下所示:db2batch -d DSS_DB -f QUERY1.SQL -i complete -iso CS -o p 5 o 5 r 0 -r test1.results.txt
文件 test1.results.txt 將包含編譯和運行查詢所用的時間,如下所示:* Prepare Time is: 7.278206 seconds
* Execute Time is: 107.729436 seconds
* Fetch Time is: 0.000102 seconds
* Elapsed Time is: 115.007744 seconds (complete)
練習: 在步驟 1A 中,在 SALES_FACT 表上創建了外鍵約束,但是,它們可能會影響插入、更新和刪除操作,因為數據庫治理器必須實施參照完整性。假如這些操作的性能很要害,并且參照完整性可由其它方法來實施,那么可以創建信息型約束,以繼續利用連接排除。否則,提供信息型約束會導致不正確的結果。 信息型約束與參照約束的定義類似,只是最后加上了 not enforced 要害字,例如: ALTER TABLE SKAPOOR.SALES_FACT ADD CONSTRAINT DATE_DIM_FK FOREIGN KEY (DATE_ID) REFERENCES DATE_DIM NOT ENFORCED; 接下來,為了完成該練習,還需撤銷在 SALES_FACT 表上創建的外鍵約束,并使用信息約束重復步驟 1A 至 1D。 方法 2:復制維度表上的物化查詢表 這里的測試使用的查詢和表與方法 1 相同,但是該方法還重復創建維度表上的 MQT。 在方法 1 中,維度表在不同的分區中,必須在分區之間傳送數據。可以使用 MQT 將維度表復制到其它分區,以支持合并連接,避免在分區之間發送數據,從而提高查詢執行性能。 步驟 2A:創建重復的 MQT:db2 -tvf replicated.ddl
清單 28. replicated.ddl 文件的內容connect to dss_db;
drop table skapoor.store_dim_rep;
drop table skapoor.product_dim_rep;
drop table skapoor.date_dim_rep;
create table skapoor.store_dim_rep as (select * from skapoor.store_dim)
data initially deferred refresh deferred in FACT_SMS replicated;
create table skapoor.product_dim_rep as (select * from skapoor.product_dim)
data initially deferred refresh deferred in FACT_SMS replicated;
create table skapoor.date_dim_rep as (select * from skapoor.date_dim)
data initially deferred refresh deferred in FACT_SMS replicated;
refresh table skapoor.store_dim_rep;
refresh table skapoor.product_dim_rep;
refresh table skapoor.date_dim_rep;
create index skapoor.store_dim_id_rep on skapoor.store_dim_rep (store_id);
create index skapoor.product_dim_id_rep on skapoor.product_dim_rep (product_id);
create index skapoor.date_dim_id_rep on skapoor.date_dim_rep (date_id);
runstats on table skapoor.store_dim_rep with distribution and indexes all;
runstats on table skapoor.product_dim_rep with distribution and indexes all;
runstats on table skapoor.date_dim_rep with distribution and indexes all;
connect reset;
為了確保可以實現這種合并,重復的維度必須與事實表位于同一數據庫分區組中。為簡單起見,我們使用和事實表一樣的表空間,但是,只要是共用相同的數據庫分區組,也可以使用不同的表空間。而且,為了使優化器在計算不同備選訪問計劃的成本時,重復的表與底層表一致,重復的表應該有與底層表一樣的索引,并且應該收集相同的統計信息。由于不能在 MQT 上創建惟一的索引,所以在底層表的主鍵上創建常規索引。 復制維度表會產生該表的一個額外的副本。在 DB2 9 中,新增了行壓縮功能,以節省存儲空間。為了減少維度表的額外副本的開銷,可以對其進行壓縮。當決定使用那樣的技術時,建議也壓縮重復的 MQT。否則,優化器可能會決定執行與底層維度表的非合并連接,因為它們被壓縮過,在規模上小于重復的 MQT。 步驟 2B:更新數據庫 DSS_DB 的數據庫配置,將 dft_refresh_age 設置為 "ANY",以便優化器選擇重復的 MQT: 清單 29. 更新數據庫配置db2_all db2 update db cfg for DSS_DB using dft_refresh_age any
db2 terminate
步驟 2C:和 方法 1 中的步驟 1C 一樣,生成主查詢的 db2exfmt 輸出。查看訪問計劃,看重復的 MQT 是否被訪問(也就是說,是否選擇了 date_dim_rep、product_dim_rep 和 store_dim_rep)。打開 下載 小節中的 Test 2,看看這個訪問計劃的一個例子。 在上述訪問計劃中,不存在方法 1 中那樣的連接之間的表隊列(TQ)操作符,因為優化器選擇使用重復的維度表,從而答應合并連接。 步驟 2D:確認訪問計劃中會訪問 MQT 之后,像 方法 1 中的步驟 1D 那樣,使用 db2batch 工具評測性能。在運行 db2batch 之前,應確保 db2 實例經過再循環過程。然后,記錄下結果。 注重:對于該方法,要將數據庫配置參數 DFT_REFRESH_AGE 設置為 ANY on all Database Partitions。假如想再次運行方法 1 中的測試,則需要將 DFT_REFRESH_AGE 數據庫配置參數更新為 "0"。否則,就會使用重復的 MQT,而不是使用基本維度表。 練習 1、使用行壓縮來壓縮基本維度表 STORE_DIM、PRODUCT_DIM 和 DATE_DIM。您將需要重新收集所有這三個維度表的統計信息。重新收集好統計信息后,重復步驟 2C 至 2D。 2、假如優化器沒有選擇訪問第一個練習中的重復 MQT,則重復這個練習,并壓縮重復的 MQT。 方法 3:使用重復的維度上的 MQT 的 MDC 事實表 這個測試類似于 方法 2,但是用一個 MDC 事實表替代了 SALES_FACT 表。MDC 提供了自動集群表中多個維上的數據的自動化方法,假如選擇了適當的維度列和 EXTENTSIZE 大小,可以顯著提供查詢性能。 步驟 3A:計算 EXTENTSIZE 大小。 這里為表空間選擇 12 作為 EXTENTSIZE 大小,計算方法如下: 請參閱 Info Center 中的指南,獲得 MDC 表維度方面的幫助,這里選擇 (date_id,store_id) 列作為 MDC 表的維度。 下面的查詢用于計算 sales_fact 表中 (date_id, store_id) 的惟一組合的數量: 清單 30. 計算 (date_id, store_id) 惟一組合的數量的查詢WITH TMP (DATE_ID, STORE_ID) AS
(SELECT DISTINCT DATE_ID, STORE_ID FROM SALES_FACT)
SELECT COUNT(*) AS CELL_COUNT FROM TMP;
CELL_COUNT
-----------
73097
下面的查詢計算平均每單元行數(RPC)、最小每單元行數以及最大每單元行數。 清單 31. 確定評價行數WITH CELL_TABLE(DATE_ID,STORE_ID,RPC) AS
(
SELECT DISTINCT DATE_ID,STORE_ID, COUNT(*)
FROM SALES_FACT
GROUP BY DATE_ID,STORE_ID
)
SELECT
AVG(RPC) AS RPC, MIN(RPC) AS MINRPC, MAX(RPC) AS MAXRPC
FROM CELL_TABLE;
RPC MINRPC MAXRPC
----------- ----------- -----------
298 1 380
1 record(s) selected.
為了計算每個單元的間距,我們使用 DB2 9 治理指南中 Space requirements for user table data 小節中的以下公式。 數據庫中用于每個用戶表的 4KB 頁面的數量可以這樣來估計。首先,確定平均行長度。在我們的例子中,列采用固定數據類型,因此可以將每個列的長度相加,得到行的長度。可以使用下面的 DESCRIBE 語句獲得列長度: 清單 32. DESCRIBE 語句DB2 DESCRIBE SELECT * FROM SALES_FACT
SQLDA Information
sqldaid : SQLDA sqldabc: 896 sqln: 20 sqld: 6
Column Information
sqltype sqllen sqlname.data sqlname.length
-------------------- ------ ------------------------------ --------------
385 DATE 10 DATE_ID 7
497 INTEGER 4 PRODUCT_ID 10
497 INTEGER 4 STORE_ID 8
497 INTEGER 4 QUANTITY 8
497 INTEGER 4 PRICE 5
453 CHARACTER 100 TRANSACTION_DETAILS 8
在 DESCRIBE 語句的結果中,"sqllen" 列表明每個列的長度。 計算每頁平均記錄數量的公式為: RECORDS_PER_PAGE = ROUND DOWN( 4028 / (AVG ROW SIZE + 10)) 在我們的例子中,AVG ROW SIZE = 126 字節(列長度的總和:10+4+4+4+4+100)。 因此,RECORDS_PER_PAGE = ROUND DOWN (4028 / (126+10)) = 29。 RECORDS_PER_PAGE 公式中額外的 10 個字節用于開銷。 存儲 298 條記錄(清單 31 中的 RPC)所需的 4K 頁面的數量可以這樣計算: NUMBER_OF_PAGES = (NUMBER_OF_RECORDS / RECORDS_PER_PAGE) * 1.1 where NUMBER_OF_RECORDS = RPC=298 NUMBER_OF_PAGES = ( 298 records / 29 records per page ) * 1.1 = 11.3 ~ 12 4K pages 因此,EXTENTSIZE 為 12。 步驟 3B:創建 EXTENTSIZE 大小為 12 的 MDC 表空間: 清單 33. 創建 MDC 表空間db2 -tvf mdc_tablespace.ddl -z mdc_tablespace.log
清單 34. mdc_tablespace.ddl 的內容CREATE REGULAR TABLESPACE FACT_SMS_MDC_EX IN DATABASE PARTITION GROUP
FACT_GROUP PAGESIZE 4096 MANAGED BY SYSTEM
USING ('d:databasefact_tbsp_mdc_EX120') ON DBPARTITIONNUMS (0)
USING ('d:databasefact_tbsp_mdc_EX121') ON DBPARTITIONNUMS (1)
USING ('d:databasefact_tbsp_mdc_EX122') ON DBPARTITIONNUMS (2)
USING ('d:databasefact_tbsp_mdc_EX123') ON DBPARTITIONNUMS (3)
EXTENTSIZE 12
PREFETCHSIZE 24
BUFFERPOOL IBMDEFAULTBP
OVERHEAD 7.500000
TRANSFERRATE 0.060000
NO FILE SYSTEM CACHING
DROPPED TABLE RECOVERY ON;
步驟 3C:創建 MDC 表 清單 35. 創建 MDC 表db2 -tvf sales_fact_mdc.ddl -z sales_fact_mdc.log
清單 36. sales_fact_mdc.ddl 文件的內容CONNECT TO DSS_DB;
---------------------------------------------------------
-- DDL Statements for table "SKAPOOR "."SALES_FACT_MDC_1"
---------------------------------------------------------
CREATE TABLE "SKAPOOR "."SALES_FACT_MDC_1" (
"DATE_ID" DATE ,
"PRODUCT_ID" INTEGER ,
"STORE_ID" INTEGER ,
"QUANTITY" INTEGER ,
"PRICE" INTEGER ,
"RESERVE" CHAR(100) )
DISTRIBUTE BY HASH("DATE_ID")
IN "FACT_SMS_MDC_EX"
ORGANIZE BY (
( "DATE_ID" ) ,
( "STORE_ID" ) )
;
COMMIT WORK;
CONNECT RESET;
注重:用于 MDC 表的塊索引是在事實表維列(date_id, store_id)上自動創建的。 步驟 3D:將數據插入 MDC 表。在我們的測試環境中,將數據插入 MDC 表大約花了 4 個小時。 清單 37. 將數據插入 MDC 表db2 -tvf sales_fact_mdc_insert_alter.ddl -z sales_fact_mdc_insert.log
清單 38. sales_fact_mdc_insert_alter.ddl 的內容CONNECT TO DSS_DB;
VALUES(CURRENT TIMESTAMP);
-----------------------------------
-- SET OPTLEVEL 0 TO FAVOUR INDEX access TO IMPROVE PERFORMANCE OF INSERT.
SET CURRENT QUERY OPTIMIZATION 0;
-----------------------------------
-- INSERTING THE DATA IN THE ORDER OF THE MDC COLUMNS IMPROVES
-- THE PERFORMANCE OF THE INSERT.
INSERT INTO SKAPOOR.SALES_FACT_MDC_1 SELECT *
FROM SKAPOOR.SALES_FACT ORDER BY DATE_ID,STORE_ID;
ALTER TABLE SKAPOOR.SALES_FACT_MDC_1
ADD CONSTRAINT DATE_DIM_FK FOREIGN KEY (DATE_ID) REFERENCES SKAPOOR.DATE_DIM;
ALTER TABLE SKAPOOR.SALES_FACT_MDC_1
ADD CONSTRAINT STORE_DIM_FK FOREIGN KEY (STORE_ID) REFERENCES SKAPOOR.STORE_DIM;
ALTER TABLE SKAPOOR.SALES_FACT_MDC_1
ADD CONSTRAINT PRODUCT_DIM_FK FOREIGN KEY (PRODUCT_ID)
REFERENCES SKAPOOR.PRODUCT_DIM;
VALUES(CURRENT TIMESTAMP);
RUNSTATS ON TABLE SKAPOOR.SALES_FACT_MDC_1 WITH DISTRIBUTION AND INDEXES ALL;
步驟 3E:修改 清單 2 中的查詢,將表名從 "SALES_FACT" 改為 "SALES_FACT_MDC_1",以測試 MDC 的優點。下面的清單 39 描述了新的查詢。像方法 1 的步驟 1C 一樣,以解釋模式編譯該查詢,并生成主查詢的 db2exfmt 輸出。檢查訪問計劃是否使用了 MDC 索引,并且看上去像 下載 小節中的 Test 3。 清單 39. MDC 查詢WITH TMP1 (MONTH_1,STORE,REGION,DISTRICT,AMOUNT_1) AS
( SELECT
D.MONTH AS MONTH,
S.STORE_ID AS STORE_ID,
S.DISTRICT AS DISTRICT,
S.REGION AS REGION,
SUM(F1.QUANTITY * F1.PRICE) AS AMOUNT
FROM
SKAPOOR.SALES_FACT_MDC_1 F1,
SKAPOOR.DATE_DIM D,
SKAPOOR.PRODUCT_DIM P,
SKAPOOR.STORE_DIM S
WHERE
P.MODEL LIKE '%model%' AND
F1.DATE_ID=D.DATE_ID AND
F1.PRODUCT_ID=P.PRODUCT_ID AND
F1.STORE_ID=S.STORE_ID AND
F1.DATE_ID BETWEEN '2006-01-01' AND '2006-01-31' AND
F1.STORE_ID IN (29, 30, 42, 55, 67, 72, 82, 99, 123, 199) AND
D.MONTH = 1
GROUP BY
S.STORE_ID,S.DISTRICT,S.REGION,D.MONTH) ,
TMP2 (MONTH_11,STORE,REGION,DISTRICT,AMOUNT_11) AS
( SELECT
D1.MONTH AS MONTH,
S1.STORE_ID AS STORE_ID,
S1.DISTRICT AS DISTRICT,
S1.REGION AS REGION,
SUM(F2.QUANTITY * F2.PRICE) AS AMOUNT
FROM
SKAPOOR.SALES_FACT_MDC_1 F2,
SKAPOOR.DATE_DIM D1,
SKAPOOR.PRODUCT_DIM P1,
SKAPOOR.STORE_DIM S1
WHERE
P1.MODEL LIKE '%model%' AND
F2.DATE_ID=D1.DATE_ID AND
F2.PRODUCT_ID=P1.PRODUCT_ID AND
F2.STORE_ID=S1.STORE_ID AND
F2.DATE_ID BETWEEN '2006-11-01' AND '2006-11-30' AND
F2.STORE_ID IN (29, 30, 42, 55, 67, 72, 82, 99, 123, 199) AND
D1.MONTH=11
GROUP BY
S1.STORE_ID,S1.DISTRICT,S1.REGION,D1.MONTH)
SELECT
A.*,
B.*
FROM
TMP1 A LEFT OUTER JOIN TMP2 B ON
(A.STORE=B.STORE AND A.REGION=B.REGION AND A.DISTRICT=B.DISTRICT)
ORDER BY A.AMOUNT_1 DESC, B.AMOUNT_11 DESC;
步驟 3F:像 方法 1 中的步驟 1D 那樣,將實例再循環,然后使用 db2batch 工具評測性能。 注重:QUERY1.SQL 文件中的查詢被更改,以反映 清單 39 中的查詢。記錄下結果。 方法 4:表分區和重復的維度上的 MQT 這個測試類似于 方法 2,但是用一個表分區事實表替代了 SALES_FACT 表。表分區是 DB2 9 中的新功能。它是一種數據組織模式,按照這種模式,根據一個或多個表列中的值,表數據被劃分到多個被稱作數據分區的存儲對象中。每個數據分區是一個單獨的物理實體,可以在不同的表空間中,也可以在相同的表空間中,或者兩者相結合。這種模式對于 BI 環境中非常大的表比較有益,它可以簡化數據的轉入(roll-in)和轉出(roll-out),根據應用的謂詞避免掃描不需要訪問的分區,從而提高查詢執行效率。 步驟 4A:創建分區表 第一步是確定適當的分區范圍。日期經常用于作為分區范圍,因此我們將根據 SALES_FACT 的 DATE_ID 列對表進行分區。Info Center 提供了關于定義分區表范圍的更多具體信息。 由于 SALES_FACT 表由全年的事務組成,而我們的查詢是比較各個月份的銷售量,因此每個范圍由一個月的數據組成。 為了演示分區表對數據轉入的簡化作用,先從包含一月份這個范圍的分區表開始,然后附加表示接下來每個月的分區: 清單 40. 創建分區 SALES_FACT 表db2 -tvf tablepart.ddl -z tablepart.log
清單 41. tablepart.ddl 的內容CONNECT TO DSS_DB;
CREATE REGULAR TABLESPACE FACT_TPART_SMS IN DATABASE PARTITION GROUP FACT_GROUP
PAGESIZE 4096 MANAGED BY SYSTEM
USING ('d:databasefact_tpart_tbsp0') ON DBPARTITIONNUMS (0)
USING ('d:databasefact_tpart_tbsp1') ON DBPARTITIONNUMS (1)
USING ('d:databasefact_tpart_tbsp2') ON DBPARTITIONNUMS (2)
USING ('d:databasefact_tpart_tbsp3') ON DBPARTITIONNUMS (3)
EXTENTSIZE 32
PREFETCHSIZE AUTOMATIC
BUFFERPOOL IBMDEFAULTBP
OVERHEAD 7.500000
TRANSFERRATE 0.060000
NO FILE SYSTEM CACHING;
-- CREATE THE SALES_FACT TABLE PARTITIONED ON DATE_ID
-- WITH A SINGLE PARTITION TO START WITH, CONTAINING
-- ALL SALES FROM JANUARY
CREATE TABLE "SKAPOOR "."SALES_FACT_TPART" (
"DATE_ID" DATE ,
"PRODUCT_ID" INTEGER ,
"STORE_ID" INTEGER ,
"QUANTITY" INTEGER ,
"PRICE" INTEGER ,
"TRANSACTION_DETAILS" CHAR(100) )
DISTRIBUTE BY HASH("DATE_ID")
IN "FACT_TPART_SMS"
PARTITION BY ("DATE_ID")
(PART Jan STARTING ('1/1/2006') ENDING ('1/31/2006'))
;
VALUES (CURRENT TIMESTAMP);
-- POPULATE THE SALES FROM JAN
INSERT INTO "SKAPOOR"."SALES_FACT_TPART"
SELECT * FROM "SKAPOOR"."SALES_FACT"
WHERE DATE_ID BETWEEN '1/1/2006' AND '1/31/2006';
commit work;
VALUES (CURRENT TIMESTAMP);
-- CREATE TABLES FOR SALES FROM EACH MONTH
-- WHICH WILL THEN BE ATTACHED TO SALES_FACT_TPART TABLE
CREATE TABLE "SKAPOOR"."SALES_FEB" (
"DATE_ID" DATE ,
"PRODUCT_ID" INTEGER ,
"STORE_ID" INTEGER ,
"QUANTITY" INTEGER ,
"PRICE" INTEGER ,
"TRANSACTION_DETAILS" CHAR(100) )
DISTRIBUTE BY HASH("DATE_ID")
IN "FACT_TPART_SMS";
CREATE TABLE "SKAPOOR"."SALES_MAR" (
"DATE_ID" DATE ,
"PRODUCT_ID" INTEGER ,
"STORE_ID" INTEGER ,
"QUANTITY" INTEGER ,
"PRICE" INTEGER ,
"TRANSACTION_DETAILS" CHAR(100) )
DISTRIBUTE BY HASH("DATE_ID")
IN "FACT_TPART_SMS";
CREATE TABLE "SKAPOOR"."SALES_APR" (
"DATE_ID" DATE ,
"PRODUCT_ID" INTEGER ,
"STORE_ID" INTEGER ,
"QUANTITY" INTEGER ,
"PRICE" INTEGER ,
"TRANSACTION_DETAILS" CHAR(100) )
DISTRIBUTE BY HASH("DATE_ID")
IN "FACT_TPART_SMS";
CREATE TABLE "SKAPOOR"."SALES_MAY" (
"DATE_ID" DATE ,
"PRODUCT_ID" INTEGER ,
"STORE_ID" INTEGER ,
"QUANTITY" INTEGER ,
"PRICE" INTEGER ,
"TRANSACTION_DETAILS" CHAR(100) )
DISTRIBUTE BY HASH("DATE_ID")
IN "FACT_TPART_SMS";
CREATE TABLE "SKAPOOR"."SALES_JUN" (
"DATE_ID" DATE ,
"PRODUCT_ID" INTEGER ,
"STORE_ID" INTEGER ,
"QUANTITY" INTEGER ,
"PRICE" INTEGER ,
"TRANSACTION_DETAILS" CHAR(100) )
DISTRIBUTE BY HASH("DATE_ID")
IN "FACT_TPART_SMS";
CREATE TABLE "SKAPOOR"."SALES_JUL" (
"DATE_ID" DATE ,
"PRODUCT_ID" INTEGER ,
"STORE_ID" INTEGER ,
"QUANTITY" INTEGER ,
"PRICE" INTEGER ,
"TRANSACTION_DETAILS" CHAR(100) )
DISTRIBUTE BY HASH("DATE_ID")
IN "FACT_TPART_SMS";
CREATE TABLE "SKAPOOR"."SALES_AUG" (
"DATE_ID" DATE ,
"PRODUCT_ID" INTEGER ,
"STORE_ID" INTEGER ,
"QUANTITY" INTEGER ,
"PRICE" INTEGER ,
"TRANSACTION_DETAILS" CHAR(100) )
DISTRIBUTE BY HASH("DATE_ID")
IN "FACT_TPART_SMS";
CREATE TABLE "SKAPOOR"."SALES_SEP" (
"DATE_ID" DATE ,
"PRODUCT_ID" INTEGER ,
"STORE_ID" INTEGER ,
"QUANTITY" INTEGER ,
"PRICE" INTEGER ,
"TRANSACTION_DETAILS" CHAR(100) )
DISTRIBUTE BY HASH("DATE_ID")
IN "FACT_TPART_SMS";
CREATE TABLE "SKAPOOR"."SALES_OCT" (
"DATE_ID" DATE ,
"PRODUCT_ID" INTEGER ,
"STORE_ID" INTEGER ,
"QUANTITY" INTEGER ,
"PRICE" INTEGER ,
"TRANSACTION_DETAILS" CHAR(100) )
DISTRIBUTE BY HASH("DATE_ID")
IN "FACT_TPART_SMS";
CREATE TABLE "SKAPOOR"."SALES_NOV" (
"DATE_ID" DATE ,
"PRODUCT_ID" INTEGER ,
"STORE_ID" INTEGER ,
"QUANTITY" INTEGER ,
"PRICE" INTEGER ,
"TRANSACTION_DETAILS" CHAR(100) )
DISTRIBUTE BY HASH("DATE_ID")
IN "FACT_TPART_SMS";
CREATE TABLE "SKAPOOR"."SALES_DEC" (
"DATE_ID" DATE ,
"PRODUCT_ID" INTEGER ,
"STORE_ID" INTEGER ,
"QUANTITY" INTEGER ,
"PRICE" INTEGER ,
"TRANSACTION_DETAILS" CHAR(100) )
DISTRIBUTE BY HASH("DATE_ID")
IN "FACT_TPART_SMS";
VALUES (CURRENT TIMESTAMP);
-- POPULATE EACH TABLE WITH SALES FOR THE CORRESPONDING MONTH
INSERT INTO "SKAPOOR"."SALES_FEB"
SELECT * FROM "SKAPOOR"."SALES_FACT"
WHERE DATE_ID BETWEEN '2/1/2006' AND '2/28/2006';
commit work;
INSERT INTO "SKAPOOR"."SALES_MAR"
SELECT * FROM "SKAPOOR"."SALES_FACT"
WHERE DATE_ID BETWEEN '3/1/2006' AND '3/31/2006';
commit work;
INSERT INTO "SKAPOOR"."SALES_APR"
SELECT * FROM "SKAPOOR"."SALES_FACT"
WHERE DATE_ID BETWEEN '4/1/2006' AND '4/30/2006';
commit work;
INSERT INTO "SKAPOOR"."SALES_MAY"
SELECT * FROM "SKAPOOR"."SALES_FACT"
WHERE DATE_ID BETWEEN '5/1/2006' AND '5/31/2006';
commit work;
INSERT INTO "SKAPOOR"."SALES_JUN"
SELECT * FROM "SKAPOOR"."SALES_FACT"
WHERE DATE_ID BETWEEN '6/1/2006' AND '6/30/2006';
commit work;
INSERT INTO "SKAPOOR"."SALES_JUL"
SELECT * FROM "SKAPOOR"."SALES_FACT"
WHERE DATE_ID BETWEEN '7/1/2006' AND '7/31/2006';
commit work;
INSERT INTO "SKAPOOR"."SALES_AUG"
SELECT * FROM "SKAPOOR"."SALES_FACT"
WHERE DATE_ID BETWEEN '8/1/2006' AND '8/31/2006';
commit work;
INSERT INTO "SKAPOOR"."SALES_SEP"
SELECT * FROM "SKAPOOR"."SALES_FACT"
WHERE DATE_ID BETWEEN '9/1/2006' AND '9/30/2006';
commit work;
INSERT INTO "SKAPOOR"."SALES_OCT"
SELECT * FROM "SKAPOOR"."SALES_FACT"
WHERE DATE_ID BETWEEN '10/1/2006' AND '10/31/2006';
commit work;
INSERT INTO "SKAPOOR"."SALES_NOV"
SELECT * FROM "SKAPOOR"."SALES_FACT"
WHERE DATE_ID BETWEEN '11/1/2006' AND '11/30/2006';
commit work;
INSERT INTO "SKAPOOR"."SALES_DEC"
SELECT * FROM "SKAPOOR"."SALES_FACT"
WHERE DATE_ID BETWEEN '12/1/2006' AND '12/31/2006';
commit work;
VALUES (CURRENT TIMESTAMP);
-- Attach SALES from February and March
ALTER TABLE "SKAPOOR"."SALES_FACT_TPART"
ATTACH PARTITION Feb STARTING FROM '2/1/2006' ENDING AT '2/28/2006'
FROM "SKAPOOR"."SALES_FEB";
ALTER TABLE "SKAPOOR"."SALES_FACT_TPART"
ATTACH PARTITION Mar STARTING FROM '3/1/2006' ENDING AT '3/31/2006'
FROM "SKAPOOR"."SALES_MAR";
-- Make the partitions visible
SET INTEGRITY FOR "SKAPOOR"."SALES_FACT_TPART"
IMMEDIATE CHECKED;
commit work;
-- Attach SALES from April to June
ALTER TABLE "SKAPOOR"."SALES_FACT_TPART"
ATTACH PARTITION Apr STARTING FROM '4/1/2006' ENDING AT '4/30/2006'
FROM "SKAPOOR"."SALES_APR";
ALTER TABLE "SKAPOOR"."SALES_FACT_TPART"
ATTACH PARTITION May STARTING FROM '5/1/2006' ENDING AT '5/31/2006'
FROM "SKAPOOR"."SALES_MAY";
ALTER TABLE "SKAPOOR"."SALES_FACT_TPART"
ATTACH PARTITION Jun STARTING FROM '6/1/2006' ENDING AT '6/30/2006'
FROM "SKAPOOR"."SALES_JUN";
SET INTEGRITY FOR "SKAPOOR"."SALES_FACT_TPART"
IMMEDIATE CHECKED;
commit work;
-- Attach SALES from July to Dec
ALTER TABLE "SKAPOOR"."SALES_FACT_TPART"
ATTACH PARTITION Jul STARTING FROM '7/1/2006' ENDING AT '7/31/2006'
FROM "SKAPOOR"."SALES_JUL";
ALTER TABLE "SKAPOOR"."SALES_FACT_TPART"
ATTACH PARTITION Aug STARTING FROM '8/1/2006' ENDING AT '8/31/2006'
FROM "SKAPOOR"."SALES_AUG";
ALTER TABLE "SKAPOOR"."SALES_FACT_TPART"
ATTACH PARTITION Sep STARTING FROM '9/1/2006' ENDING AT '9/30/2006'
FROM "SKAPOOR"."SALES_SEP";
ALTER TABLE "SKAPOOR"."SALES_FACT_TPART"
ATTACH PARTITION Oct STARTING FROM '10/1/2006' ENDING AT '10/31/2006'
FROM "SKAPOOR"."SALES_OCT";
ALTER TABLE "SKAPOOR"."SALES_FACT_TPART"
ATTACH PARTITION Nov STARTING FROM '11/1/2006' ENDING AT '11/30/2006'
FROM "SKAPOOR"."SALES_NOV";
ALTER TABLE "SKAPOOR"."SALES_FACT_TPART"
ATTACH PARTITION Dec STARTING FROM '12/1/2006' ENDING AT '12/31/2006'
FROM "SKAPOOR"."SALES_DEC";
SET INTEGRITY FOR "SKAPOOR"."SALES_FACT_TPART"
IMMEDIATE CHECKED;
yo
commit work;
VALUES(CURRENT TIMESTAMP);
RUNSTATS ON TABLE SKAPOOR.SALES_FACT_TPART WITH DISTRIBUTION;
commit work;
CONNECT RESET;
在我們的測試環境中,填充所有分區花了大約 3 個小時。而將表附加(attach)到每個分區則比較快。表一旦被附加到分區之后,它就成為 SALES_FACT_TPART 表的一個物理實體,不能再將其當作單獨的表來查詢。假如想那樣做的話,必須將表與 SALES_FACT_TPART 表分離開來。 步驟 4B:修改 清單 2 中的查詢,將表名從 "SALES_FACT" 改為 "SALES_FACT_TPART",以測試分區消除的優點。下面的清單 42 描述了這個新的查詢。像 方法 1 的步驟 1C 那樣,以解釋模式編譯該查詢,并生成主查詢的 db2exfmt 輸出。檢查訪問計劃是否使用了分區表,這就像 下載 小節中的 TPART。 清單 42. 分區表查詢WITH TMP1 (MONTH_1,STORE,REGION,DISTRICT,AMOUNT_1) AS
( SELECT
D.MONTH AS MONTH,
S.STORE_ID AS STORE_ID,
S.DISTRICT AS DISTRICT,
S.REGION AS REGION,
SUM(F1.QUANTITY * F1.PRICE) AS AMOUNT
FROM
SKAPOOR.SALES_FACT_TPART F1,
SKAPOOR.DATE_DIM D,
SKAPOOR.PRODUCT_DIM P,
SKAPOOR.STORE_DIM S
WHERE
P.MODEL LIKE '%model%' AND
F1.DATE_ID=D.DATE_ID AND
F1.PRODUCT_ID=P.PRODUCT_ID AND
F1.STORE_ID=S.STORE_ID AND
F1.DATE_ID BETWEEN '2006-01-01' AND '2006-01-31' AND
F1.STORE_ID IN (29, 30, 42, 55, 67, 72, 82, 99, 123, 199) AND
D.MONTH = 1
GROUP BY
S.STORE_ID,S.DISTRICT,S.REGION,D.MONTH) ,
TMP2 (MONTH_11,STORE,REGION,DISTRICT,AMOUNT_11) AS
( SELECT
D1.MONTH AS MONTH,
S1.STORE_ID AS STORE_ID,
S1.DISTRICT AS DISTRICT,
S1.REGION AS REGION,
SUM(F2.QUANTITY * F2.PRICE) AS AMOUNT
FROM
SKAPOOR.SALES_FACT_TPART F2,
SKAPOOR.DATE_DIM D1,
SKAPOOR.PRODUCT_DIM P1,
SKAPOOR.STORE_DIM S1
WHERE
P1.MODEL LIKE '%model%' AND
F2.DATE_ID=D1.DATE_ID AND
F2.PRODUCT_ID=P1.PRODUCT_ID AND
F2.STORE_ID=S1.STORE_ID AND
F2.DATE_ID BETWEEN '2006-11-01' AND '2006-11-30' AND
F2.STORE_ID IN (29, 30, 42, 55, 67, 72, 82, 99, 123, 199) AND
D1.MONTH=11
GROUP BY
S1.STORE_ID,S1.DISTRICT,S1.REGION,D1.MONTH)
SELECT
A.*,
B.*
FROM
TMP1 A LEFT OUTER JOIN TMP2 B ON
(A.STORE=B.STORE AND A.REGION=B.REGION AND A.DISTRICT=B.DISTRICT)
ORDER BY A.AMOUNT_1 DESC, B.AMOUNT_11 DESC;
在 db2exfmt 輸出中,關于分區表訪問的具體信息表明是否發生了分區排除以及訪問了哪些分區: 14) TBSCAN: (Table Scan)
Cumulative Total Cost: 15378
Cumulative CPU Cost: 8.77067e+008
Cumulative I/O Cost: 15213
Cumulative Re-Total Cost: 15378
Cumulative Re-CPU Cost: 8.77065e+008
Cumulative Re-I/O Cost: 15213
Cumulative First Row Cost: 8.22883
Cumulative Comm Cost: 0
Cumulative First Comm Cost: 0
Estimated Bufferpool Buffers: 15213
Arguments:
---------
DPESTFLG: (Number of data partitions accessed are Estimated)
FALSE
DPLSTPRT: (List of data partitions accessed)
10
DPNUMPRT: (Number of data partitions accessed)
1
...
DP Elim Predicates:
------------------
Range 1)
Stop Predicate: (Q10.DATE_ID <= '11/30/2006')
Start Predicate: ('11/01/2006' <= Q10.DATE_ID)
...
DPESTFLG 參數指示是估計分區消除(TRUE)還是在編譯時精確計算分區消除(FALSE)。假如已估計,那么在運行時確定實際的分區消除。在這個例子中,分區消除是在編譯時計算的。DPLSTPRT 參數指示訪問哪些分區,DPNUMPRT 指示所訪問的分區的數量。假如 DPESTFLG 為 TRUE,那么這兩個值由優化器估算。在這個例子中,只有一個分區,即分區 10 被訪問。其余分區被忽略。 DP Elim Predicates 部分列出了用于確定訪問哪些分區的謂詞。 步驟 4C:像 方法 1 中的步驟 1D 那樣,對實例進行再循環,并使用 db2batch 工具評測性能。 注重:QUERY1.SQL 文件中的查詢被修改,以反映清單 42 中的查詢。記錄下結果。 練習 1、索引可以幫助提高使用分區表 SALES_FACT_TPART 的查詢的性能。創建一個或多個可能有用的索引,并重復步驟 4B 和 4C。別忘了收集關于索引的統計信息。 2、試著將一個或多個分區與 SALES_FACT_TPART 表分離開來,感覺一下如何通過使用分區表輕松而有效地轉出數據。 方法 5:表分區、MDC 和重復的維度上的 MQT 這個測試類似于 方法 4,但是用一個分區 MDC 事實表替代了 SALES_FACT_TPART 表。可以將 MDC 和表分區相結合,進一步提高查詢的性能。與 方法 3 采用了相同的技術,使用 DATE_ID 和 STORE_ID 列作為維列,采用了與方法 4 一樣的范圍和 DATE_ID。 步驟 5A:創建分區 MDC 表 清單 43. 創建分區 MDC SALES_FACT 表db2 -tvf tablepart_mdc.ddl -z tablepart_mdc.log
清單 44. tablepart_mdc.ddl 的內容CONNECT TO DSS_DB;
CREATE TABLE "SKAPOOR "."SALES_FACT_TPART_MDC" ( "DATE_ID" DATE ,
"PRODUCT_ID" INTEGER ,
"STORE_ID" INTEGER ,
"QUANTITY" INTEGER ,
"PRICE" INTEGER ,
"TRANSACTION_DETAILS" CHAR(100))
DISTRIBUTE BY HASH("DATE_ID")
PARTITION BY RANGE("DATE_ID")
(PART "JAN" STARTING('2006-01-01') ENDING('2006-01-31') IN "FACT_TPART_SMS",
PART "FEB" STARTING('2006-02-01') ENDING('2006-02-28') IN "FACT_TPART_SMS",
PART "MAR" STARTING('2006-03-01') ENDING('2006-03-31') IN "FACT_TPART_SMS",
PART "APR" STARTING('2006-04-01') ENDING('2006-04-30') IN "FACT_TPART_SMS",
PART "MAY" STARTING('2006-05-01') ENDING('2006-05-31') IN "FACT_TPART_SMS",
PART "JUN" STARTING('2006-06-01') ENDING('2006-06-30') IN "FACT_TPART_SMS",
PART "JUL" STARTING('2006-07-01') ENDING('2006-07-31') IN "FACT_TPART_SMS",
PART "AUG" STARTING('2006-08-01') ENDING('2006-08-31') IN "FACT_TPART_SMS",
PART "SEP" STARTING('2006-09-01') ENDING('2006-09-30') IN "FACT_TPART_SMS",
PART "OCT" STARTING('2006-10-01') ENDING('2006-10-31') IN "FACT_TPART_SMS",
PART "NOV" STARTING('2006-11-01') ENDING('2006-11-30') IN "FACT_TPART_SMS",
PART "DEC" STARTING('2006-12-01') ENDING('2006-12-31') IN "FACT_TPART_SMS")
ORGANIZE BY (
DATE_ID,
STORE_ID)
;
COMMIT WORK ;
INSERT INTO SKAPOOR.SALES_FACT_TPART_MDC
SELECT * FROM SKAPOOR.SALES_FACT_MDC_1;
COMMIT WORK;
RUNSTATS ON TABLE SKAPORR.SALES_FACT_TPART_MDC WITH DISTRIBUTION AND INDEXES ALL;
COMMIT WORK;
CONNECT RESET;
步驟 5B: 修改 清單 2 中的查詢,將表名從 "SALES_FACT" 改為 "SALES_FACT_TPART_MDC",以測試將 MDC 與分區消除相結合的優點。下面的清單 45 描述了這個新的查詢。像 方法 1 的步驟 1C 那樣,以解釋模式編譯該查詢,并生成主查詢的 db2exfmt 輸出。檢查訪問計劃是否使用了分區表和塊索引,它看上去像 下載 小節中的 TPART_MDC 一樣 。 清單 45. 分區 MDC 表查詢WITH TMP1 (MONTH_1,STORE,REGION,DISTRICT,AMOUNT_1) AS
( SELECT
D.MONTH AS MONTH,
S.STORE_ID AS STORE_ID,
S.DISTRICT AS DISTRICT,
S.REGION AS REGION,
SUM(F1.QUANTITY * F1.PRICE) AS AMOUNT
FROM
SKAPOOR.SALES_FACT_TPART_MDC F1,
SKAPOOR.DATE_DIM D,
SKAPOOR.PRODUCT_DIM P,
SKAPOOR.STORE_DIM S
WHERE
P.MODEL LIKE '%model%' AND
F1.DATE_ID=D.DATE_ID AND
F1.PRODUCT_ID=P.PRODUCT_ID AND
F1.STORE_ID=S.STORE_ID AND
F1.DATE_ID BETWEEN '2006-01-01' AND '2006-01-31' AND
F1.STORE_ID IN (29, 30, 42, 55, 67, 72, 82, 99, 123, 199) AND
D.MONTH = 1
GROUP BY
S.STORE_ID,S.DISTRICT,S.REGION,D.MONTH) ,
TMP2 (MONTH_11,STORE,REGION,DISTRICT,AMOUNT_11) AS
( SELECT
D1.MONTH AS MONTH,
S1.STORE_ID AS STORE_ID,
S1.DISTRICT AS DISTRICT,
S1.REGION AS REGION,
SUM(F2.QUANTITY * F2.PRICE) AS AMOUNT
FROM
SKAPOOR.SALES_FACT_TPART_MDC F2,
SKAPOOR.DATE_DIM D1,
SKAPOOR.PRODUCT_DIM P1,
SKAPOOR.STORE_DIM S1
WHERE
P1.MODEL LIKE '%model%' AND
F2.DATE_ID=D1.DATE_ID AND
F2.PRODUCT_ID=P1.PRODUCT_ID AND
F2.STORE_ID=S1.STORE_ID AND
F2.DATE_ID BETWEEN '2006-11-01' AND '2006-11-30' AND
F2.STORE_ID IN (29, 30, 42, 55, 67, 72, 82, 99, 123, 199) AND
D1.MONTH=11
GROUP BY
S1.STORE_ID,S1.DISTRICT,S1.REGION,D1.MONTH)
SELECT
A.*,
B.*
FROM
TMP1 A LEFT OUTER JOIN TMP2 B ON
(A.STORE=B.STORE AND A.REGION=B.REGION AND A.DISTRICT=B.DISTRICT)
ORDER BY A.AMOUNT_1 DESC, B.AMOUNT_11 DESC;
步驟 5C:像 方法 1 中的步驟 1D 那樣,將實例再循環,然后使用 db2batch 工具評測性能。 注重:QUERY1.SQL 文件中的查詢被更改,以反映清單 39 中的查詢。記錄下結果。 方法 6:使用 MQT 預先計算聚合結果 這個測試類似于 方法 1,但是增加 MQT,以便預先計算聚合值。使用 MQT 物化表達為聚合的結果可以顯著提高查詢性能。在 清單 2 中描述的每個查詢中,向外連接的每個分支由相同連接上的一個聚合組成。惟一的不同是應用于事實表的本地謂詞。假如可以在執行查詢之前預先計算連接,則可以顯著提高查詢執行性能。 步驟 6A:創建和刷新 MQT 清單 46. 創建 MQT 表db2 -tvf mqt2.ddl -z mqt2.log
清單 47. mqt2.ddl 文件的內容CONNECT TO DSS_DB;
------------------------------------------------
-- DDL STATEMENTS FOR TABLE "SKAPOOR "."MQT2"
CREATE TABLE SKAPOOR.MQT2 AS
(
SELECT
D.MONTH AS MONTH,
S.STORE_ID AS STORE_ID,
S.DISTRICT AS DISTRICT,
S.REGION AS REGION,
SUM(F1.QUANTITY * F1.PRICE) AS AMOUNT ,
F1.DATE_ID
FROM
SKAPOOR.SALES_FACT F1,
SKAPOOR.DATE_DIM D,
SKAPOOR.PRODUCT_DIM P,
SKAPOOR.STORE_DIM S
WHERE
F1.DATE_ID=D.DATE_ID AND
F1.PRODUCT_ID=P.PRODUCT_ID AND
F1.STORE_ID=S.STORE_ID AND
P.MODEL LIKE '%MODEL%'
GROUP BY S.STORE_ID,S.DISTRICT,S.REGION,D.MONTH, F1.DATE_ID
)
DATA INITIALLY DEFERRED REFRESH DEFERRED IN FACT_SMS;
REFRESH TABLE "SKAPOOR "."MQT2";
-- DDL STATEMENTS FOR INDEXES ON TABLE "SKAPOOR "."MQT2"
CREATE INDEX "SKAPOOR "."MQT2_IND3" ON "SKAPOOR "."MQT2"
("MONTH" ASC,
"DATE_ID" ASC)
ALLOW REVERSE SCANS;
-- DDL STATEMENTS FOR INDEXES ON TABLE "SKAPOOR "."MQT2"
CREATE INDEX "SKAPOOR "."MQT2_IND4" ON "SKAPOOR "."MQT2"
("DATE_ID" ASC,
"STORE_ID" ASC,
"DISTRICT" ASC,
"REGION" ASC,
"MONTH" ASC,
"AMOUNT" ASC)
ALLOW REVERSE SCANS;
清單 41 中創建的兩個索引 MQT2_IND3 和 MQT2_IND4 用于提高從 MQT 訪問數據的性能。 步驟 6B: 收集關于 MQT 統計信息,并調整模式,以符合您的環境: 清單 48. 收集關于 MQT 表的統計信息DB2 RUNSTATS ON TABLE SKAPOOR.MQT2 WITH DISTRIBUTION AND INDEXES ALL
步驟 6C:像 方法 1 的 STEP 1C 那樣,解釋 清單 2 中的查詢,并生成 db2exfmt 輸出。然后,查看訪問計劃。應該可以看到,訪問計劃選擇 MQT 和 MQT2,并使用一個連接操作符,以完成兩個 MQT 的向外連接。這個訪問計劃看上去應該類似于 下載 小節中的 Test 6。 假如沒有選擇 MQT,則應確保在所有數據庫分區上的數據庫配置中 DFT_REFRESH_AGE 被設為 "ANY";否則,優化器不會考慮 MQT。 STEP 6D: 像 方法 1 中的步驟 1D 那樣,將實例再循環,并使用 db2batch 工具評測性能。 現在,記錄下結果。 考察每種方法對查詢執行性能的效果 注重:所有測試都是在沒有其它其他活動在運行的環境中執行的。 下面的表列出了在我們的系統上使用 db2batch 工具測到的每種方法所用的時間(單位為秒)。方法 | 查詢 | 所用時間(秒) |
1. 參照完整性約束 | 清單 2 | 115.00 |
2. 重復的 MQT | 清單 2 | 103.42 |
3. 多維集群和重復的 MQT | 清單 39 | 38.36 |
4. 表分區和重復的 MQT | 清單 42 | 197.74 |
5. 表分區、MDC 和重復的 MQT | 清單 45 | 32.21 |
6. 使用 MQT 預先計算聚合結果 | 清單 2 | 7.61 |
新聞熱點
疑難解答