日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

在 DB2 優(yōu)化器中使用分布統(tǒng)計(jì)信息

 Youyoudb 2016-08-26

簡(jiǎn)介

為了執(zhí)行查詢(xún)或 DML 語(yǔ)句(INSERTUPDATE、DELETE),DB2 必須創(chuàng)建一個(gè)訪問(wèn)計(jì)劃(access plan)。訪問(wèn)計(jì)劃定義按什么順序訪問(wèn)表,使用哪些索引,以及用何種連接(join)方法來(lái)關(guān)聯(lián)數(shù)據(jù)。好的訪問(wèn)計(jì)劃對(duì)于 SQL 語(yǔ)句的快速執(zhí)行至關(guān)重要。DB2 優(yōu)化器可以創(chuàng)建訪問(wèn)計(jì)劃。這是一種基于成本的優(yōu)化器,這意味著它是根據(jù)表和索引的相關(guān)統(tǒng)計(jì)信息來(lái)作出決策的。DB2 在生成統(tǒng)計(jì)信息時(shí),不但能提供基本統(tǒng)計(jì)信息,還允許創(chuàng)建所謂的分布統(tǒng)計(jì)信息。不但數(shù)據(jù)庫(kù)管理員要理解分布統(tǒng)計(jì)信息,而且應(yīng)用程序開(kāi)發(fā)人員也要理解分布統(tǒng)計(jì)信息。應(yīng)用程序開(kāi)發(fā)人員必須小心謹(jǐn)慎,因?yàn)樵谀承┣闆r下分布統(tǒng)計(jì)信息對(duì)于 DB2 優(yōu)化器來(lái)說(shuō)非常重要。主變量或參數(shù)標(biāo)記(在 Java 中為 java.sql.PreparedStatement)的使用可能會(huì)造成阻礙,使優(yōu)化器無(wú)法最大限度地利用分布統(tǒng)計(jì)信息。本文解釋什么是分布統(tǒng)計(jì)信息、分布統(tǒng)計(jì)信息在哪些情況下尤為重要,以及應(yīng)用程序開(kāi)發(fā)人員應(yīng)該考慮些什么,才能使 DB2 優(yōu)化器創(chuàng)建有效的訪問(wèn)計(jì)劃。


基本統(tǒng)計(jì)信息和分布統(tǒng)計(jì)信息

在研究分布統(tǒng)計(jì)信息之前,我們先來(lái)看看基本統(tǒng)計(jì)信息,只要執(zhí)行 RUNSTATS 即可收集這些表的相關(guān)統(tǒng)計(jì)信息。

表的相關(guān)統(tǒng)計(jì)信息:

  • 當(dāng)前使用的頁(yè)面數(shù)
  • 包含記錄行的頁(yè)面數(shù)
  • 溢出的行數(shù)
  • 表中的行數(shù)(基數(shù))
  • 對(duì)于 MDC 表,還有包含數(shù)據(jù)的塊(block)數(shù)

表中各列的相關(guān)統(tǒng)計(jì)信息:

  • 列的基數(shù)
  • 列的平均長(zhǎng)度
  • 列中第二大的值
  • 列中第二小的值
  • 列中 NULL 值的個(gè)數(shù)

通常,執(zhí)行 RUNSTATS 時(shí),不但可以收集到關(guān)于表的統(tǒng)計(jì)信息,而且還可以收集到相應(yīng)的索引的相關(guān)統(tǒng)計(jì)信息。要了解為索引而收集的統(tǒng)計(jì)信息,請(qǐng)參閱 DB2 Administration Guide: Performance - Statistical information that is collected。

觀察一個(gè)表的基本統(tǒng)計(jì)信息,您可以看到,DB2 優(yōu)化器知道一個(gè)表由多少行組成(表的基數(shù)),以及一個(gè)列包含多少個(gè)不同的值(列的基數(shù))。但是,還有一些信息是基本統(tǒng)計(jì)信息無(wú)法提供的。例如,基本統(tǒng)計(jì)信息不能告訴優(yōu)化器一個(gè)列中某些值出現(xiàn)的頻率。假設(shè)表 TABLE_X 有大約 1,000,000 行,在該表上執(zhí)行這樣一條查詢(xún):

SELECT * FROM TABLE_X WHERE COLUMN_Y = 'VALUE_Z'

難道 DB2 優(yōu)化器知道 TABLE_X 中有多少行滿(mǎn)足條件 COLUMN_Y = 'VALUE_Z' 不重要嗎?換句話(huà)說(shuō):知道這個(gè)查詢(xún)將返回 1 行、100 行、1000 行還是 10000 行有什么不好呢?

實(shí)際上,通過(guò)基本統(tǒng)計(jì)信息,DB2 優(yōu)化器只能估計(jì) 'VALUE_Z' 在 COLUMN_Y 中出現(xiàn)的頻率。在這種情況下,優(yōu)化器認(rèn)為所有值在 COLUMN_Y 中是平均分布的,這意味著它認(rèn)為所有的值都有相同的出現(xiàn)頻率。如果事實(shí)碰巧如此,這樣估計(jì)并無(wú)大礙。但是,如果有些值比其他值出現(xiàn)得更頻繁一些(例如,如果 'VALUE_Z' 出現(xiàn) 900,000 次,即占所有行的 90%),那么優(yōu)化器不能考慮到這一點(diǎn),因而生成的訪問(wèn)計(jì)劃就不是最優(yōu)的。而分布統(tǒng)計(jì)信息可以填補(bǔ)這一空白。分布統(tǒng)計(jì)信息可以提供關(guān)于數(shù)據(jù)出現(xiàn)頻率及其分布情況的信息,如果數(shù)據(jù)庫(kù)中存儲(chǔ)了很多重復(fù)值,并且數(shù)據(jù)在表中并非平均分布的時(shí)候,分布統(tǒng)計(jì)信息對(duì)于基本統(tǒng)計(jì)信息是一個(gè)重要的補(bǔ)充。


分布統(tǒng)計(jì)信息----頻率分布統(tǒng)計(jì)信息和分位數(shù)分布統(tǒng)計(jì)信息

有兩種不同類(lèi)型的分布統(tǒng)計(jì)信息 —— 頻率統(tǒng)計(jì)信息和分位數(shù)統(tǒng)計(jì)信息。讓我們通過(guò)一個(gè)示例表來(lái)研究一下這兩種不同類(lèi)型的分布統(tǒng)計(jì)信息。

示例表 “CARS” 表示一家汽車(chē)制造商,對(duì)于生產(chǎn)的每一輛汽車(chē),在表中都有相應(yīng)的一行。每輛汽車(chē)可以由它的 ID 來(lái)標(biāo)識(shí),因此 “ID” 是表 “CARS” 的主鍵(PK)。此外,表中有一個(gè) “STATE” 列,表明汽車(chē)當(dāng)前處在制造流程中的哪一步。一輛汽車(chē)的制造流程從第 1 步開(kāi)始,然后是第 2 步、第 3 步,...、第 49 步、第 50 步、第 51 步、...、第 98 步、第 99 步,一直到第 100 步 —— 第 100 步意味著汽車(chē)已經(jīng)完工了。已完工的汽車(chē)所對(duì)應(yīng)的行仍然保留在表中,后續(xù)流程(例如投訴管理、質(zhì)量保證等)仍要用到這些行。汽車(chē)制造商生產(chǎn) 10 種不同型號(hào)(“TYPE” 列)的汽車(chē)。為了簡(jiǎn)化問(wèn)題,在這個(gè)示例表中,各種汽車(chē)型號(hào)命名為 A、B、C、D、...、J。除主鍵索引(在 “ID” 列上)之外,“STATE” 列上也有一個(gè)索引(“I_STATE”),在 “TYPE” 列上還有一個(gè)索引(“I_TYPE”)。實(shí)際上,一個(gè) “CARS” 表包含的列遠(yuǎn)不止 “ID”、“STATE” 和 “TYPE”。為簡(jiǎn)單起見(jiàn),示例表中沒(méi)有出現(xiàn)其他這些列。

頻率分布統(tǒng)計(jì)信息

假設(shè)表 CARS 現(xiàn)在有大約 1,000,000 條記錄,不同的型號(hào)在表中出現(xiàn)的頻率如下所示:

薩1. 表 CARS 中 TYPE 列的頻率統(tǒng)計(jì)信息
TYPECOUNT(TYPE)
A506135
B301985
C104105
D52492
E19584
F10123
G4876
H4589
I4403
J3727

型號(hào)為 A 的汽車(chē)最受購(gòu)買(mǎi)者的青睞,因此生產(chǎn)的汽車(chē)中大約有 50% 是這種型號(hào)。型號(hào) B 和型號(hào) C 僅次于型號(hào) A ,分別占所有汽車(chē)的 30% 和 10%。其他所有型號(hào)加在一起僅占 10%。

上面的表顯示了 “TYPE” 列的頻率統(tǒng)計(jì)信息。通過(guò)基本統(tǒng)計(jì)信息,DB2 優(yōu)化器只能了解到該表包含 1,000,000 行(表的基數(shù))和 10 種不同的值(型號(hào)),即 A 到 J。如果沒(méi)有分布統(tǒng)計(jì)信息,優(yōu)化器會(huì)認(rèn)為每種值以相同的頻率出現(xiàn),大約都是出現(xiàn) 100,000 次。而一旦生成了關(guān)于 “TYPE” 列的分布統(tǒng)計(jì)信息,優(yōu)化器即可了解每種型號(hào)真正的出現(xiàn)頻率。因此,優(yōu)化器清楚各種已有型號(hào)出現(xiàn)的不同頻率。

優(yōu)化器使用頻率統(tǒng)計(jì)信息來(lái)計(jì)算用于檢查相等或不等的謂詞的過(guò)濾因子。例如:

SELECT * FROM CARS WHERE TYPE = 'H';

分位數(shù)分布統(tǒng)計(jì)信息

與頻率統(tǒng)計(jì)信息不同,分位數(shù)統(tǒng)計(jì)信息與不同值的出現(xiàn)頻率無(wú)關(guān),而與一個(gè)表中有多少行小于或大于某個(gè)值(或者有多少行介于兩個(gè)值之間)相關(guān)。分位數(shù)統(tǒng)計(jì)信息提供關(guān)于一個(gè)列中的值是否聚合的信息。為獲得這樣的信息,DB2 假定列中的值是按升序排列的,并根據(jù)正則行間隔確定相應(yīng)的值。

我們來(lái)看看表 CARS 中的 “STATE” 列,該列按升序排列。根據(jù)正則行間隔,即可確定 “STATE” 的對(duì)應(yīng)值。

2CARS 表中 STATE 列的分位數(shù)統(tǒng)計(jì)信息
COUNT(row)STATE ASC
54791
5494810
10999021
15988531
21505042
26525152
32016763
37005773
42487284
47508794
504298100
...100
1012019100

由于已完工的汽車(chē)仍然沒(méi)有從表中刪除,因此狀態(tài)為 100 (=完工)的汽車(chē)數(shù)量比所有處于其他狀態(tài)的汽車(chē)總和還多。已完工的汽車(chē)占表中所有記錄的 50%。

注意: 在實(shí)際情況下,已完工的汽車(chē)數(shù)量甚至還要更多(例如超過(guò) 99%)。在后文中的具體例子中可看到這種情況。

上表顯示了 “STATE” 列的分位數(shù)統(tǒng)計(jì)信息。有了這種關(guān)于有多少行分別小于和大于確定值的信息,優(yōu)化器即可計(jì)算出用于測(cè)試小于(小于等于)、大于(大于等于)或介于兩值之間的謂詞的過(guò)濾因子。例如:

SELECT * FROM CARS WHERE STATE <>

SELECT * FROM CARS WHERE STATE BETWEEN 50 AND 70

根據(jù)已有的分位數(shù)統(tǒng)計(jì)信息計(jì)算出來(lái)的過(guò)濾因子不是很精確,但即使只收集 20 個(gè)值,其誤差仍然低于 5%。


DB2優(yōu)化器對(duì)分布統(tǒng)計(jì)信息的使用--示例

如何創(chuàng)建訪問(wèn)計(jì)劃

要為 SQL 語(yǔ)句創(chuàng)建訪問(wèn)計(jì)劃,最簡(jiǎn)單的方法就是使用 Visual Explain Tool,這是 DB2 Command Center 中的一個(gè)工具。如果您想使用命令行創(chuàng)建一個(gè)更詳細(xì)的訪問(wèn)計(jì)劃,那么可以按如下步驟操作:

  1. 創(chuàng)建 Explain 表(只需創(chuàng)建一次): 
    從下面的目錄中可以找到用于生成 Explain 表的腳本:
    • UNIX/Linux:/sqllib/misc/EXPLAIN.DDL
    • Windows:\SQLLIB\MISC\EXPLAIN.DDL
  2. 用 DB2 CLP 執(zhí)行該腳本: 
    db2 CONNECT TO USER  

    db2 -tf EXPLAIN.DDL 

    db2 CONNECT RESET

  3. 執(zhí)行以下 SQL 語(yǔ)句,填充 Explain 表: 
    db2 CONNECT TO USER  

    db2 SET CURRENT EXPLAIN MODE EXPLAIN 

    db2  

    db2 SET CURRENT EXPLAIN MODE NO 

    db2 CONNECT RESET

  4. 讀取 Explain 表,并將訪問(wèn)計(jì)劃寫(xiě)入一個(gè)文件: 
    db2exfmt -d -u -g -o -w -1 -n % -s % -# 0

我們來(lái)看一個(gè)完整的示例,在此例中,DB2 優(yōu)化器可以使用分布統(tǒng)計(jì)信息來(lái)更合理地估計(jì)過(guò)濾因子,以便生成更好的訪問(wèn)計(jì)劃。

這個(gè)示例查詢(xún)從已經(jīng)定義好的 CARS 表中讀取數(shù)據(jù)。對(duì)于表 CARS 中的汽車(chē)數(shù)據(jù),有以下假設(shè):

  • 該表的基數(shù)為 1,000,000,也就是說(shuō)該表包含 1,000,000 行。
  • 表中 99.9% 的汽車(chē)是已經(jīng)完工(“STATE” 列 = 100)的,這些汽車(chē)的信息相關(guān)必須保留,以用于后續(xù)處理(投述管理、質(zhì)量保證等)。剩下的 1,000 輛汽車(chē)目前還處在制造流程中。
  • 在該表中,制造商提供的從 A 到 J 的 10 種不同汽車(chē)型號(hào)(“TYPE” 列)幾乎以相同的頻率出現(xiàn)。

注意: 腳本 create_table_cars.sql 用于創(chuàng)建前述 CARS 表,包括 “STATE” 列和 “TYPE” 列上的索引,該腳本可以通過(guò)本文 下載。這個(gè)示例表是在 DB2 SAMPLE 數(shù)據(jù)庫(kù)中(命令 db2sampl),使用 DBM CFG 和 DB CFG 的默認(rèn)設(shè)置創(chuàng)建的。

示例查詢(xún)選擇型號(hào)為 A 且正處在制造流程中、尚未完工的所有汽車(chē):

SELECT * FROM CARS WHERE STATE < 100="" and="" type='A'>

首先來(lái)分析一下,在沒(méi)有分布統(tǒng)計(jì)信息,而只有 CARS 表的基本統(tǒng)計(jì)信息及其索引的情況下,優(yōu)化器選擇的訪問(wèn)計(jì)劃是怎樣的。


1. 沒(méi)有分布統(tǒng)計(jì)信息時(shí)示例查詢(xún)的訪問(wèn)計(jì)劃
沒(méi)有分布統(tǒng)計(jì)信息時(shí)示例查詢(xún)的訪問(wèn)計(jì)劃 

由于優(yōu)化器不知道 STATE 值不是均勻分布的,因此它決定使用索引 I_TYPE。使用這個(gè)索引會(huì)帶來(lái)較高的成本,因?yàn)樵谠L問(wèn) CARS 表之前,需要從索引中讀取大約 100,000 個(gè) RID(記錄 ID)。此外,對(duì)于查詢(xún)返回行數(shù)的假設(shè)也是錯(cuò)誤的。因?yàn)閮?yōu)化器認(rèn)為所有制造步驟(從 1 到 100)都有相同的頻率,所以它無(wú)法預(yù)知謂詞 STATE <> 將過(guò)濾掉大量有價(jià)值的行。但是您知道,事實(shí)是在所有 1,000,000 輛汽車(chē)中,只有 1,000 輛汽車(chē)正處在生成流程中。

在沒(méi)有分布統(tǒng)計(jì)信息的情況下,執(zhí)行該查詢(xún)時(shí),動(dòng)態(tài) SQL 的一個(gè)快照返回以下監(jiān)視器值(假定所需的監(jiān)視器開(kāi)關(guān)已激活):

Number of executions = 1Number of compilations = 1Worst preparation time (ms) = 9Best preparation time (ms) = 9Internal rows deleted = 0Internal rows inserted = 0Rows read = 99336Internal rows updated = 0Rows written = 0Statement sorts = 0Statement sort overflows = 0Total sort time = 0Buffer pool data logical reads = 8701Buffer pool data physical reads = 8131Buffer pool temporary data logical reads = 0Buffer pool temporary data physical reads = 0Buffer pool index logical reads = 165Buffer pool index physical reads = 155Buffer pool temporary index logical reads = 0Buffer pool temporary index physical reads = 0Total execution time (sec.ms) = 0.530903Total user cpu time (sec.ms) = 0.280403Total system cpu time (sec.ms) = 0.230332Statement text = SELECT ID, TYPE, STATE FROM SAMPLE.CARS WHERE STATE < 100="" and="" type='A'>

在此,我們不會(huì)進(jìn)一步分析這些值,但是請(qǐng)記住它們,以便與有分布統(tǒng)計(jì)信息時(shí)相同查詢(xún)得到的監(jiān)視器值相比較。

接下來(lái),為 CARS 表生成分布統(tǒng)計(jì)信息,并再次執(zhí)行查詢(xún)。此時(shí),優(yōu)化器選擇了以下訪問(wèn)計(jì)劃:

如何閱讀訪問(wèn)計(jì)劃

訪問(wèn)計(jì)劃顯示在執(zhí)行某條 SQL 語(yǔ)句時(shí),數(shù)據(jù)庫(kù)引擎必須執(zhí)行的所有操作。訪問(wèn)計(jì)劃呈倒置樹(shù)型,需要從下往上讀。其中為各操作顯示以下信息:

  • 估計(jì)該操作將返回的行數(shù)
  • 操作的類(lèi)型。例如: 
    TBSCAN = 表掃描 
    IXSCAN = 索引掃描 
    FETCH = 從表中獲取數(shù)據(jù) 
    NLJOIN = 嵌套的循環(huán)連接 
    SORT = 排序
  • 用于惟一標(biāo)識(shí)操作的一個(gè)數(shù)字
  • 該操作的預(yù)計(jì)總成本
  • 該操作的預(yù)計(jì) I/O 成本

成本用 timerons 來(lái)表達(dá),這是一個(gè)人造的單位,不能解釋為實(shí)際時(shí)間單位,但有助于判斷一個(gè)操作和整個(gè)訪問(wèn)計(jì)劃的開(kāi)銷(xiāo)。成本是累積的,因?yàn)槊總€(gè)操作的成本都要加到之前所有操作的成本上。

有分布統(tǒng)計(jì)信息時(shí)的訪問(wèn)計(jì)劃 

這個(gè)訪問(wèn)計(jì)劃的成本明顯低于沒(méi)有分布統(tǒng)計(jì)信息時(shí)的成本:前者為 203.809,而后者為 3242.63。這是因?yàn)閮?yōu)化器現(xiàn)在知道,謂詞STATE <> 有一個(gè)較高的過(guò)濾因子,因而只會(huì)返回大約 1,000 輛正處在生產(chǎn)流程中尚未完工的汽車(chē)。因此,在這種情況下,CARS 表不是使用索引 I_TYPE 來(lái)訪問(wèn)的,而是使用索引 I_STATE 來(lái)訪問(wèn)的。此外,現(xiàn)在可以正確地估計(jì)結(jié)果集中的總行數(shù)?,F(xiàn)有 1,000 輛汽車(chē)尚未完工,不同的型號(hào)出現(xiàn)頻率相同。故結(jié)果集中包含大約 100 行。

有分布統(tǒng)計(jì)信息時(shí)的訪問(wèn)計(jì)劃要優(yōu)于沒(méi)有分布統(tǒng)計(jì)信息時(shí)的訪問(wèn)計(jì)劃。但是,這是否會(huì)影響查詢(xún)的執(zhí)行時(shí)間?清單 2 包含相應(yīng)的監(jiān)視器數(shù)據(jù)快照:

Number of executions = 1Number of compilations = 1Worst preparation time (ms) = 9Best preparation time (ms) = 9Internal rows deleted = 0Internal rows inserted = 0Rows read = 1000Internal rows updated = 0Rows written = 0Statement sorts = 1Statement sort overflows = 0Total sort time = 5Buffer pool data logical reads = 11Buffer pool data physical reads = 10Buffer pool temporary data logical reads = 0Buffer pool temporary data physical reads = 0Buffer pool index logical reads = 12Buffer pool index physical reads = 9Buffer pool temporary index logical reads = 0Buffer pool temporary index physical reads = 0Total execution time (sec.ms) = 0.014597Total user cpu time (sec.ms) = 0.000000Total system cpu time (sec.ms) = 0.010014Statement text = SELECT ID, TYPE, STATE FROM SAMPLE.CARS WHERE STATE < 100="" and="" type='A'>

下表 比較了有分布統(tǒng)計(jì)信息和沒(méi)有分布統(tǒng)計(jì)信息這兩種不同情況下的快照監(jiān)視器值:.較快照監(jiān)視器值

快照值無(wú)分布統(tǒng)計(jì)信息有分布統(tǒng)計(jì)信息
Rows read99,3361,000
Buffer pool data logical reads8,70111
Buffer pool index logical reads16512
Total execution time (sec.ms)0.5309030.014597

您可以看到,有分布統(tǒng)計(jì)信息的情況下,DB2 執(zhí)行查詢(xún)時(shí)需要計(jì)算的行數(shù)更少。這對(duì)于 CPU 成本和 I/O 成本都有積極的影響。最重要的是總執(zhí)行成本,因?yàn)榭倛?zhí)行成本關(guān)系到應(yīng)用程序的響應(yīng)時(shí)間。在具有分布統(tǒng)計(jì)信息的情況下,這個(gè)時(shí)間是 0.014597 秒,而在沒(méi)有分布統(tǒng)計(jì)信息的情況下,這個(gè)時(shí)間是 0.530903,相差 36 倍之多。

在我們的示例中,兩種情況下的執(zhí)行時(shí)間分別為 0.014597 秒和 0.530903 秒,這個(gè)差距還不夠明顯,因?yàn)檫@兩個(gè)值只是次秒級(jí)的。然而,這樣的差距不應(yīng)被忽略。如果要執(zhí)行更復(fù)雜的查詢(xún),或者要連續(xù)執(zhí)行多個(gè)查詢(xún),那么執(zhí)行時(shí)間的差距就不是次秒級(jí)的,而是以秒甚至分鐘來(lái)計(jì)算的。


分布統(tǒng)計(jì)信息的生成

如前所述,在使用 RUNSTATS 命令生成統(tǒng)計(jì)信息時(shí),并不是 總會(huì)收集分布統(tǒng)計(jì)信息。這是有意義的,因?yàn)閮H在存在很多重復(fù)值或者數(shù)據(jù)分布不均勻的情況下,分布統(tǒng)計(jì)信息才重要。而在其他情況下,分布統(tǒng)計(jì)信息并不能帶來(lái)多大的好處。

下面的 RUNSTATS 命令只收集 CARS 表(在模式 SAMPLE 中)和相應(yīng)索引的基本統(tǒng)計(jì)信息:

RUNSTATS ON TABLE SAMPLE.CARS AND INDEXES ALL

此外,如果需要收集 CARS 表中所有列的分布統(tǒng)計(jì)信息(頻率統(tǒng)計(jì)信息和分位數(shù)統(tǒng)計(jì)信息),那么可以執(zhí)行以下命令:

RUNSTATS ON TABLE SAMPLE.CARS WITH DISTRIBUTION AND INDEXES ALL

生成分布統(tǒng)計(jì)信息意味著給 DB2 帶來(lái)額外的、可觀的開(kāi)銷(xiāo),從而影響 RUNSTATS 命令的執(zhí)行時(shí)間。所以,應(yīng)該只為那些需要分布統(tǒng)計(jì)信息的列生成分布統(tǒng)計(jì)信息。

RUNSTATS ON TABLE SAMPLE.CARS WITH DISTRIBUTION ON COLUMNS (TYPE, STATE) AND INDEXES ALL

應(yīng)為滿(mǎn)足以下條件的列收集分布統(tǒng)計(jì)信息:

  • 該列有很多重復(fù)的值(頻率統(tǒng)計(jì)信息),或者該列的值分布不均勻,即它們?cè)谀承┚植渴蔷酆系模ǚ治粩?shù)統(tǒng)計(jì)信息)。
  • 檢查等于或不等于的謂詞中使用到該列(頻率統(tǒng)計(jì)信息),或者檢查小于(小于等于)、大于(大于等于)或介于兩個(gè)值之間的謂詞中使用到該列(分位數(shù)統(tǒng)計(jì)信息)。

對(duì)于頻率統(tǒng)計(jì)信息,重要的是定義好收集多少個(gè)值的重復(fù)數(shù)。如果為一個(gè)列中的所有值收集頻率統(tǒng)計(jì)信息,那么成本就太高了。如果在執(zhí)行 RUNSTATS 時(shí)沒(méi)有顯式定義數(shù)量,那么 DB2 將使用由數(shù)據(jù)庫(kù)參數(shù) NUM_FREQVALUES 提供的默認(rèn)數(shù)量。由于NUM_FREQVALUES 的默認(rèn)值為 10,DB2 將為列中出現(xiàn)最頻率的 10 個(gè)值收集重復(fù)次數(shù),這里假定 RUNSTATS 是在沒(méi)有顯式定義數(shù)量,且數(shù)據(jù)庫(kù)參數(shù) NUM_FREQVALUES 沒(méi)有被修改的情況下執(zhí)行的。

與頻率統(tǒng)計(jì)信息類(lèi)似,也必須為分位數(shù)統(tǒng)計(jì)信息定義一個(gè)數(shù)量,以保證精確性。分位數(shù)統(tǒng)計(jì)信息定義應(yīng)該使用多少 “度量值(measurement)“。列中的值被認(rèn)為是按升序排列的,并且有一個(gè)正則的行間隔,相應(yīng)的值是確定的。使用的度量值越多,優(yōu)化器對(duì)于檢查范圍(、>、<>、>=BETWEEN)的謂詞的過(guò)濾因子的估計(jì)就越準(zhǔn)確。如果在執(zhí)行 RUNSTATS 時(shí)沒(méi)有明確指定一個(gè)值,那么 DB2 將使用由數(shù)據(jù)庫(kù)參數(shù) NUM_QUANTILES 提供的默認(rèn)數(shù)量。NUM_QUANTILES 的默認(rèn)值是 20,也就是說(shuō)使用 20 個(gè)度量值。這已經(jīng)是一個(gè)較好的值,因?yàn)樗梢员WC優(yōu)化器在使用分位數(shù)統(tǒng)計(jì)信息的情況下對(duì)確定過(guò)濾因子的估計(jì)誤差最大只有 5%。

如果數(shù)據(jù)庫(kù)配置(DB CFG)不能提供 NUM_FREQVALUES 和 NUM_QUANTILES 的值,那么可以在執(zhí)行 RUNSTATS 時(shí)顯式定義:

RUNSTATS ON TABLE SAMPLE.CARS WITH DISTRIBUTION ON COLUMNS (TYPE NUM_FREQVALUES 10 NUM_QUANTILES 20, STATE NUM_FREQVALUES 15 NUM_QUANTILES 30) AND INDEXES ALL


如何檢查是否存在分布統(tǒng)計(jì)信息

為檢查某個(gè)表的分布統(tǒng)計(jì)信息是否已收集,可以查看分類(lèi)視圖 SYSCAT.COLDIST 的內(nèi)容:

SELECT * FROM SYSCAT.COLDIST WHERE TABSCHEMA = 'SAMPLE' AND TABNAME = 'CARS'

視圖 SYSCAT.COLDIST 結(jié)構(gòu)如下:

列名數(shù)據(jù)類(lèi)型是否可以為空描述
TABSCHEMAVARCHAR(128)不可以本條目對(duì)應(yīng)的表的限定符
TABNAMEVARCHAR(128)不可以本條目對(duì)應(yīng)的表的名稱(chēng)
COLNAMEVARCHAR(128)不可以本條目對(duì)應(yīng)的列的名稱(chēng)
TYPECHAR(1)不可以F = Frequency(最大頻率)
Q = 分位數(shù)值
SEQNOSMALLINT不可以如果 TYPE = F,則該列中的 N 表示第 N 頻繁的值
如果 TYPE = Q,那么該列中的 N 表示第 N 個(gè)分位數(shù)值
COLVALUEVARCHAR(254)可以數(shù)據(jù)值,其形式為字符字面值,或者一個(gè) NULL 值
VALCOUNTBIGINT不可以如果 TYPE = F,那么 VALCOUNT 是 COLVALUE 出現(xiàn)在該列中的次數(shù)
如果 TYPE = Q,那么 VALCOUNT 是其值小于或等于 COLVALUE 的行的數(shù)量
DISTCOUNTBIGINT可以如果 TYPE = Q,那么該列記錄小于或等于 COLVALUE 的不同值的數(shù)量(如果沒(méi)有,則為 NULL)

僅在收集了一個(gè)表中至少一個(gè)列的分布統(tǒng)計(jì)信息時(shí),SYSCAT.COLDIST 才會(huì)包含關(guān)于該表的條目。如果在沒(méi)有 WITH DISTRIBUTION 的情況下再次執(zhí)行 RUNSTATS,那么 SYSCAT.COLDIST 中與該表對(duì)應(yīng)的條目將被刪除。


分布統(tǒng)計(jì)信息的參數(shù)標(biāo)記/主變量

JDBC 提供了兩種途徑來(lái)執(zhí)行動(dòng)態(tài) SQL,因而也提供了兩種不同的接口:

  • java.sql.Statement
  • java.sql.PreparedStatement

PreparedStatement 是 Statement 的子接口,它允許使用參數(shù)標(biāo)記(= 占位符;在其他編程語(yǔ)言中,此類(lèi)占位符也被稱(chēng)為主變量) —— 而不是 Statement。在使用 PreparedStatement 的情況下,首先編譯要執(zhí)行的包括參數(shù)標(biāo)記的 SQL 語(yǔ)句,然后將值綁定到參數(shù)標(biāo)記,最后執(zhí)行 SQL 語(yǔ)句。

下面的代碼片段顯示使用 Statement 與使用 PreparedStatement 的不同之處。

java.sql.Connection con = ...;java.sql.Statement stmt1 = con.createStatement();String insert1 = 'INSERT INTO TABLE_X (COL_Y) VALUES ('ABC')';stmt1.executeUpdate(insert1);java.sql.Statement stmt2 = con.createStatement();String insert2 = 'INSERT INTO TABLE_X (COL_Y) VALUES ('XYZ')';stmt2.executeUpdate(insert2);con.commit();

java.sql.Connection con = ...;String insert = 'INSERT INTO TABLE_X (COL_Y) VALUES (?)';java.sql.PreparedStatement pstmt = con.prepareStatement(insert);pstmt.setString(1, 'ABC');pstmt.executeUpdate();pstmt.setString(1, 'XYZ');pstmt.executeUpdate();con.commit();

如果一條簡(jiǎn)單 SQL 語(yǔ)句執(zhí)行多次(例如示例中的 INSERT 語(yǔ)句),那么使用 PreparedStatement 有優(yōu)勢(shì),因?yàn)閿?shù)據(jù)庫(kù)只需編譯該語(yǔ)句一次,即可多次執(zhí)行,而不需要重復(fù)編譯。假設(shè)在示例中需要插入數(shù)千行記錄,那么使用 PreparedStatement 可以交付更短的執(zhí)行時(shí)間,因?yàn)橹恍枰淮螠?zhǔn)備/編譯時(shí)間,而不需要數(shù)千次。

然而,Java 開(kāi)發(fā)人員使用 PreparedStatement 往往是因?yàn)樾枰谶\(yùn)行時(shí)提供值/過(guò)濾器標(biāo)準(zhǔn)時(shí),使用這種接口編寫(xiě)的代碼更為優(yōu)雅。請(qǐng)看如下代碼片段:

int state = 100;String type = 'A';...java.sql.Connection con = ...;java.sql.Statement stmt = con.createStatement();String select = 'SELECT * FROM CARS WHERE STATE < '="" +="" state="" +="" '="" and="" type='' +="" type="" +="" ''';java.sql.resultset="" rs="stmt.executeQuery(select);while" (rs.next())="" {="">

int state = 100;String type = 'A';...java.sql.Connection con = ...;String select = 'SELECT * FROM CARS WHERE STATE < and="" type="?';java.sql.PreparedStatement" pstmt="con.prepareStatement(select);pstmt.setInt(1," state);pstmt.setstring(2,="" type);java.sql.resultset="" rs="pstmt.executeQuery();while" (rs.next())="" {="">

使用 PreparedStatement 的那種代碼片段在編碼方面更為優(yōu)雅,因?yàn)樵趯?nbsp;STATE 和 TYPE 的值置入 SQL 語(yǔ)句時(shí),不需要進(jìn)行字符串運(yùn)算。但這種方法存在一個(gè)缺點(diǎn),在綁定 WHERE 子句中謂詞的值之前,需要編譯 SELECT(創(chuàng)建訪問(wèn)計(jì)劃)。為使優(yōu)化器能夠使用可用的分布統(tǒng)計(jì)信息,帶有具體值的謂詞極為重要。

讓我們?cè)俅慰纯?CARS 表的查詢(xún)示例,但這次使用參數(shù)標(biāo)記,而不是具體值:

SELECT * FROM CARS WHERE STATE < and="" type="">

CARS 表的分布統(tǒng)計(jì)信息仍然可用,因?yàn)樵诖似陂g這些統(tǒng)計(jì)信息也已經(jīng)被收集。然而,使用參數(shù)標(biāo)記時(shí),將生成另一個(gè)訪問(wèn)計(jì)劃。

有參數(shù)標(biāo)記和分布統(tǒng)計(jì)信息時(shí)示例查詢(xún)的訪問(wèn)計(jì)劃 

雖然這個(gè)訪問(wèn)計(jì)劃比使用具體值但沒(méi)有分布統(tǒng)計(jì)信息情況下的訪問(wèn)計(jì)劃好,但不如既使用具體值又有分布統(tǒng)計(jì)信息時(shí)的訪問(wèn)計(jì)劃。在下表 中,動(dòng)態(tài) SQL 快照中的監(jiān)視器輸出也顯示了這一點(diǎn):

Number of executions = 1Number of compilations = 1Worst preparation time (ms) = 10Best preparation time (ms) = 10Internal rows deleted = 0Internal rows inserted = 0Rows read = 99Internal rows updated = 0Rows written = 0Statement sorts = 1Statement sort overflows = 0Total sort time = 0Buffer pool data logical reads = 11Buffer pool data physical reads = 10Buffer pool temporary data logical reads = 0Buffer pool temporary data physical reads = 0Buffer pool index logical reads = 268Buffer pool index physical reads = 125Buffer pool temporary index logical reads = 0Buffer pool temporary index physical reads = 0Total execution time (sec.ms) = 0.081908Total user cpu time (sec.ms) = 0.060086Total system cpu time (sec.ms) = 0.010014Statement text = SELECT ID, TYPE, STATE FROM SAMPLE.CARS WHERE STATE < and="" type="">

將這些值與之前收集到的值相比較,可以得到下表:

快照值沒(méi)有分布統(tǒng)計(jì)信息有分布統(tǒng)計(jì)信息既有分布統(tǒng)計(jì)信息又有參數(shù)標(biāo)記
Rows read99,3361,00099
Buffer pool data logical reads8,7011111
Buffer pool index logical reads16512268
Total execution time (sec.ms)0.5309030.0145970.081908

在有參數(shù)標(biāo)記時(shí)的 “Rows read” 值最小,但實(shí)際上這并不重要,因?yàn)榇藭r(shí) “Buffer pool index logical reads” 值較高。重要的是,與既有分布統(tǒng)計(jì)信息又有具體值的情況相比,“Total execution time” 更差一些,在本例中,其差距達(dá)到 8 倍。如前所述,在本例中,我們觀察的是對(duì)少量數(shù)據(jù)執(zhí)行的一個(gè)非常簡(jiǎn)單的查詢(xún)。因此,執(zhí)行時(shí)間上的差距并不是很明顯。但是,如果要執(zhí)行更復(fù)雜的查詢(xún),其執(zhí)行時(shí)間以秒/分鐘來(lái)計(jì)算,那么這個(gè)差距就會(huì)非常明顯。

這個(gè)示例表明,如果將分布統(tǒng)計(jì)信息與參數(shù)標(biāo)記一起使用,分布統(tǒng)計(jì)信息的作用就會(huì)受到限制。如果存在很多重復(fù)/不均勻的數(shù)據(jù)分布和復(fù)雜的查詢(xún),這可能會(huì)導(dǎo)致執(zhí)行時(shí)間高于未使用參數(shù)標(biāo)記情況下的執(zhí)行時(shí)間。這并不意味著使用 PreparedStatement 總是很糟糕的。相反,如果要反復(fù)執(zhí)行多次一條簡(jiǎn)單的語(yǔ)句,并且每次使用不同的值執(zhí)行,建議使用 PreparedStatement,因?yàn)檎Z(yǔ)句只需編譯一次。在處理復(fù)雜的查詢(xún)時(shí),由于這些查詢(xún)常常要向系統(tǒng)和 DSS(決策支持系統(tǒng))報(bào)告,因此使用參數(shù)標(biāo)記很可能得不償失。這是因?yàn)榉植冀y(tǒng)計(jì)信息得不到充分的利用,編譯時(shí)間只應(yīng)用了一次,因?yàn)檫@些查詢(xún)最多也只是執(zhí)行一次。


結(jié)束語(yǔ)

在本文中,您看到了 DB2 優(yōu)化器對(duì)分布統(tǒng)計(jì)信息的使用。如果一個(gè)數(shù)據(jù)庫(kù)包含很多重復(fù)的值,或者數(shù)據(jù)分布不均勻,那么,如果除了基本統(tǒng)計(jì)信息外,另外還生成了分布統(tǒng)計(jì)信息,DB2 優(yōu)化器就可為 SQL 語(yǔ)句產(chǎn)生更好的訪問(wèn)計(jì)劃。本文解釋了不同類(lèi)型的分布統(tǒng)計(jì)信息,展示如何使用 RUNSTATS 命令生成這些統(tǒng)計(jì)信息,并提供了一個(gè)示例場(chǎng)景,說(shuō)明分布統(tǒng)計(jì)信息在某些情況下的重要性。您還研究了參數(shù)標(biāo)記/主變量的使用會(huì)為 DB2 優(yōu)化器對(duì)分布統(tǒng)計(jì)信息的考慮帶來(lái)怎樣的限制。



下載

描述名字大小下載方法
DDL for sample table CARScreate_table_cars.zip1KBHTTP


轉(zhuǎn)自IBM官方文檔庫(kù):http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-0606fechner/

最后貼個(gè)英文版地址:

http://www.ibm.com/developerworks/data/library/techarticle/dm-0606fechner/index.html?S_TACT=105AGX52&S_CMP=cn-a-db2

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多