我們知道,在數據庫應用系統中,SQL 語句的性能好壞至關重要。如果 SQL 語句性能很差,可能會導致整個數據庫應用系統的性能也非常差。那么,如何監控數據庫系統中 SQL 語句的性能,導致 SQL 語句性能差的原因是什么? SQL 語句運行過程中對系統資源的使用情況如何?系統資源存在哪些瓶頸?在 Informix 11.5 中,主要提供了兩個工具來解決上述問題。一個是 set explain 命令,我們可以通過查看數據庫的查詢計划來分析導致 SQL 語句性能差的原因並給予相應的調整,另一個是 SQL 下鑽查詢特性,通過它,我們可以分析系統中哪些 SQL 語句執行比較慢、SQL 語句執行的時間是多少、SQL 語句運行時對資源的占用情況及系統存在的瓶頸是什么並及時進行相應的調整。下面,我們具體來看一下這兩種監控工具的具體使用方法,希望對大家能有所幫助。
SET EXPLAIN 命令
當我們發現系統中某一個或一組 SQL 語句性能比較差時,我們往往會使用 set explain 命令來查看一下 SQL 語句的查詢計划,看看 SQL 語句性能差的原因是什么並進行相應的調整。在 Informix 中,查詢計划主要包括訪問計划(access plan)及表連接計划(join plan)。訪問計划是指 Informix 數據庫是通過什么方法來讀取磁盤上的數據。一般來講,Informix 主要提供以下幾種訪問計划:
- 順序掃描(Sequential scan):數據庫服務器按照物理順序讀取表中的所有記錄。
- 索引掃描(Index scan):數據庫服務器讀取索引頁,並通過相應的 ROWID 來讀取相關的記錄。
- 鍵值掃描(Key-only index scan):如果讀取的相關數據包含在索引節點中,數據庫服務器就只需讀取索引,不需要再去讀取相應的數據頁。
- 鍵優先掃描(Key-first index scan):鍵優先掃描是一種索引掃描,它首先使用索引鍵過濾器來減少查詢讀取的數據量。
- 自動索引掃描(Auto-index scan):自動索引掃描特性允許數據庫服務器在一個或多個字段上自動創建臨時索引,數據庫服務器通過這個臨時索引讀取相應的數據。這個臨時索引只在查詢過程中生效。該特性在一些 OLTP 批處理操作中特別有意義,它一方面利用到索引,另一方面又不需要索引維護的開銷。
Informix 主要提供兩種表連接計划:
- 嵌套循環連接(nested-loop join):在嵌套循環連接中,將掃描第一個(或外部)表,以查找滿足查詢規則的行。對於在外部表中找到的每一行,數據庫服務器將在第二個(或內部)表中搜索其相應的行。通過索引掃描還是表掃描來訪問外部表則取決於該表。如果有過濾器,數據庫服務器首先會應用它們。如果內部表沒有索引,那么數據庫服務器就會將在表上構建索引的成本與連續掃描的成本進行比較,然后選擇成本最低的那一種方法。總成本取決於連接列上是否有索引。如果連接列上有一個索引,那么其成本會相當低;否則,數據庫服務器就必須對所有表(外部和內部表)執行表掃描。
- 哈希連接(hash join):當一個或多個連接表上沒有索引時,或者當數據庫服務器必須從所有連接表中讀取大量行時,就使用這種方法。在該方法中,需要掃描其中的一個表,通常掃描較小的那個表,用它在內存中創建一個哈希表。通過哈希函數,將具有相同哈希值的行放在一個 bucket 中。在掃描完第一個表並將它放在哈希表中之后,就掃描第二個表,並在哈希表中查找該表中的每一行,看是否可以進行連接。如果連接中有更多表,那么數據庫服務器將對每個連接表執行相同的操作。
哈希連接包含兩個動作:構建哈希(或者是我們所稱的構建階段),以及探測哈希表(或探測階段)。在構建階段,數據庫服務器讀取一個表,並且在應用所有現有過濾器之后,在內存中創建一個哈希表。可以在概念上將哈希表認為是一系列的 bucket,每個 bucket 所擁有的地址是通過應用哈希函數從鍵值導出的。在探測階段,數據庫服務器將讀取連接中的其他表,如果存在過濾器,就應用它們。在滿足過濾器條件的每個行中,數據庫服務器將對鍵應用哈希函數,並探測哈希表以查找匹配的鍵值。如果讀取的相關數據包含在索引節點中,數據庫服務器就只需讀取索引,不需要再去讀取相應的數據頁。
如何獲取查詢計划
在 Informix 中,我們可以使用 SET EXPLAIN 語句或 EXPLAIN 偽指令來顯示優化程序所選擇的查詢計划。
使用 SET EXPLAIN
SET EXPLAIN 語句的輸出顯示了查詢優化程序作出的決策。它顯示了是否已使用並行掃描、響應查詢所需的最大線程數以及用於查詢的連接類型。您可以使用 SET EXPLAIN 來查看應用程序的查詢計划。
SET EXPLAIN 語句的基本語法:
>>-SET EXPLAIN--------------------------------------------------> >--+-+-OFF-------------------+-------------------------+------->< | '-ON--+---------------+-' | | '-AVOID_EXECUTE-' | '-FILE TO--+-'filename '--+--+--------------------+-'
其中:
- ON :為每個后續查詢生成評估並將結果寫入當前目錄中的輸出文件。如果文件已經存在,那么新輸出會附加到現有文件。
- AVOID_EXECUTE :防止 SELECT、INSERT、UPDATE 或 DELETE 語句在數據庫服務器將查詢計划打印到輸出文件中時執行。
- OFF :終止 SET EXPLAIN 語句的活動,以便不再為后續查詢生成評估或不再將評估寫入輸出文件 。
- FILE TO :為每個后續查詢生成評估並使您能夠指定說明輸出文件的位置。
在發出 SET EXPLAIN OFF 語句或程序結束之前,來自 SET EXPLAIN ON 語句的輸出將定向到適當的文件。如果沒有輸入 SET EXPLAIN 語句,那么缺省行為是 OFF,並且數據庫服務器不會為查詢生成評估。
SET EXPLAIN 語句在數據庫服務器優化階段期間執行,該優化階段在您啟動查詢時開始。對於與游標相關的查詢,如果查詢已准備好且沒有主變量,那么優化在您准備期間發生。否則,優化在您打開游標時發生。
如果用戶希望了解下述 SQL 語句的查詢計划並執行下述 SQL 語句,我們可以執行:
SET EXPLAIN ON; SELECT * FROM customer, orders WHERE customer.customer_num = orders.customer_num AND customer.lname = "Higgins";
如果用戶希望了解下述 SQL 語句的查詢計划但不希望執行下述 SQL 語句,我們可以執行:
SET EXPLAIN ON AVOID_EXECUTE; SELECT * FROM customer, orders WHERE customer.customer_num = orders.customer_num AND customer.lname = "Higgins";
如果用戶希望了解下述 SQL 語句的查詢計划,並將結果輸出到自己指定的位置,我們可以執行:
SET EXPLAIN ON AVOID_EXECUTE; SET EXPLAIN FILE TO '/tmp/explain.out' SELECT * FROM customer, orders WHERE customer.customer_num = orders.customer_num AND customer.lname = "Higgins";
如果用戶不再希望了解下述 SQL 語句的查詢計划,我們可以執行:
SET EXPLAIN OFF;
當執行 SPL 例程時,它已經優化。要顯示包含在 SPL 例程中的每個 SQL 語句的查詢計划,請在執行以下任何 SQL 語句(它們總是試圖優化 SPL 例程)之前執行 SET EXPLAIN ON 語句:
CREATE PROCEDURE UPDATE STATISTICS FOR PROCEDURE
例如:使用以下語句顯示 SPL 例程的查詢計划:
SET EXPLAIN ON; UPDATE STATISTICS FOR PROCEDURE procname;
使用 AVOID_EXECUTE 選項
SET EXPLAIN ON AVOID_EXECUTE 語句為會話激活 Avoid Execute 選項,或直到執行下一個不帶 AVOID_EXECUTE 的 SET EXPLAIN OFF(或 ON)。 AVOID_EXECUTE 關鍵字將使得 DML 語句無法執行;數據庫服務器會將查詢計划打印到輸出文件中。如果為包含遠程表的查詢激活 AVOID_EXECUTE,那么查詢不會在本地或遠程站點執行。
如果設置了 AVOID_EXECUTE,數據庫服務器會發送警告消息。如果您正在使用 DB-Access,它會對所有選擇、刪除、更新或插入查詢操作顯示文本消息:
Warning! avoid_execute has been set
根據 ESQL,sqlwarn.sqlwarn7 字符設置為“ W ”。
使用 SET EXPLAIN ON 或 SET EXPLAIN OFF 語句可關閉 AVOID_EXECUTE 選項。 SET EXPLAIN ON 語句將關閉 AVOID_EXECUTE 選項,但會繼續生成查詢計划並將結果寫入輸出文件。
如果在 SPL 例程中發出 SET EXPLAIN ON AVOID_EXECUTE 語句,那么 SPL 例程和所有 DDL 語句仍然執行,但該 SPL 例程內的 DML 語句將不執行。數據庫服務器會將 SPL 例程的查詢計划打印到輸出文件。要關閉此選項,必須在 SPL 例程外執行 SET EXPLAIN ON 或 SET EXPLAIN OFF 語句。如果在執行 SPL 例程之前執行 SET EXPLAIN ON AVOID_EXECUTE 語句,那么 SPL 例程內的 DML 語句將不執行,並且數據庫服務器不會將 SPL 例程的查詢計划打印到輸出文件中。
當 AVOID_EXECUTE 生效時仍然計算查詢中的恆定函數,因為數據庫服務器會在進行優化之前計算這些函數。
例如,盡管沒有執行以下 SELECT 語句,仍計算 func( ) 函數:
SELECT * FROM orders WHERE func(10) > 5;
如果在打開 ESQL/C 程序中的游標之前執行 SET EXPLAIN ON AVOID_EXECUTE 語句,那么每個 FETCH 操作將返回找不到行的消息。但是,如果在 ESQL/C 程序打開游標后執行 SET EXPLAIN ON AVOID_EXECUTE,那么此語句不會影響游標,並將繼續返回行。
sqexplain.out 文件
在 UNIX 系統中,數據庫服務器將 SET EXPLAIN ON 語句或 EXPLAIN 偽指令的輸出寫入到 sqexplain.out 文件。
如果客戶機應用程序和數據庫服務器在同一計算機上,那么 sqexplain.out 文件存儲在當前目錄中。如果您正使用版本 5.x 或更早版本的客戶機應用程序並且 sqexplain.out 文件沒有出現在當前目錄中,那么請檢查您的主目錄查找該文件。
當當前數據庫在另一台計算機上時,sqexplain.out 文件將存儲在遠程主機上的主目錄中。
在 Windows 系統中,數據庫服務器將 SET EXPLAIN ON 語句或 EXPLAIN 偽指令的輸出寫入到文件%InformixDIR%\sqexpln\username.out。
sqexplain.out 文件內容。
sqexplain.out 文件主要分為 3 個部分:
部分 1:
部分 1 包含以下內容,它們的順序與以下列出的順序相同:
- 用於查詢的 SQL 語句。
- 以優化器用來比較計划的單位表示的查詢成本估計值。這些單位代表查詢執行的相對時間,每個單位大約相當於一次典型的磁盤存取時間。優化器選擇某個查詢計划是因為執行這個計划的估計成本在所有評估的計划中是最低的。
- 期望查詢產生的行數估計。
- 執行查詢所派生的最大數量的線程(如果設置了 PDQPRIORITY 的話)。
- 用於執行 ORDER BY 和/或 GROUP BY (如果需要的話)的臨時文件可選項。
部分 2:
表在這里是按訪問它們的順序列出的。對於每個表,列出了所應用的過濾器。
- 已訪問表的名稱
- 數據庫服務器讀取表所采取的訪問計划 — 順序掃描、索引路徑和自動索引。另外,如果表是分段的,則在這里列出對於這一特定查詢所要訪問的活動分段。
- 列出了每對表的連接計划:嵌套循環連接或動態哈希連接連接。對於動態哈希連接連接也列出了執行哈希連接連接所用到的過濾器。
部分 3:
根據所選存取計划的不同,這一部分的內容會有所不同。對於部分 2 中的每一個表,這一部分會出現一次。
對於順序掃描:本部分包含要應用的過濾器(如果有的話)。如果子查詢是過濾器的一部分,會在這里擴展它,它會象主查詢一樣包括所有的部分。
對於索引掃描和自動索引掃描:對於索引和自動索引掃描,這一部分包含以下信息:
- 一些索引鍵,將對它們應用過濾器,跟着是以下項中的一個或全部:
- 僅鍵項,如果它是只用到鍵的索引掃描。
- 聚合項,如果查詢聚合了索引鍵。
- 鍵優先項,如果對索引鍵應用鍵優先過濾器。
- 下限索引過濾器(如果有的話)。如果子查詢是過濾器的一部分,會在這里擴展它,它會象主查詢一樣包括所有的部分。
- 上限索引過濾器(如果有的話)。如果子查詢是過濾器的一部分,會在這里擴展它,它會象主查詢一樣包括所有的部分。
- 要應用的鍵優先過濾器(如果有的話)。如果子查詢是過濾器的一部分,會在這里擴展它,它會象主查詢一樣包括所有的部分。
EXPLAIN 偽指令
如果希望僅顯示一個 SQL 語句的查詢計划時,可以使用 EXPLAIN 偽指令代替 SET EXPLAIN ON 或 SET EXPLAIN ON AVOID_Execute 語句。
使用 EXPLAIN 偽指令按以下方式顯示查詢計划:
- EXPLAIN :顯示優化程序所選擇的查詢計划。
- EXPLAIN AVOID_EXECUTE :顯示優化程序所選擇的查詢計划,但是不執行查詢。
在 Informix 中,偽指令可以采用如下方法表示:
--+directive text {+directive text} /*+directive text */
下邊例子顯示了使用 EXPLAIN 偽指令的查詢語句:
select --+ explain l.customer_num, l.lname, l.company,l.phone, r.call_dtime, r.call_descr from customer l, cust_calls r where l.customer_num = r.customer_num
下邊例子顯示了使用 EXPLAIN AVOID_Execute 偽指令的查詢語句:
select --+ explain,avoid_execute l.customer_num, l.lname, l.company,l.phone, r.call_dtime, r.call_descr from customer l, cust_calls r where l.customer_num = r.customer_num
下邊顯示了使用 EXPLAIN AVOID_EXECUTE 偽指令的查詢的 sqexplain.out 文件輸出樣本:
QUERY: ------ select --+ explain ,avoid_execute l.customer_num, l.lname, l.company,l.phone, r.call_dtime, r.call_descr from customer l, cust_calls r where l.customer_num = r.customer_num DIRECTIVES FOLLOWED: EXPLAIN AVOID_EXECUTE DIRECTIVES NOT FOLLOWED: Estimated Cost: 7 Estimated # of Rows Returned: 7 1) Informix.r: SEQUENTIAL SCAN 2) Informix.l: INDEX PATH (1) Index Keys: customer_num (Serial, fragments: ALL) Lower Index Filter: Informix.l.customer_num = Informix.r.customer_num NESTED LOOP JOIN
下表對上述 sqexplain.out 文件中描述所選的查詢計划的相關輸出行進行了描述。
輸出行 | 所選的查詢計划描述 |
---|---|
DIRECTIVES FOLLOWED: EXPLAIN AVOID_EXECUTE | 使用偽指令 EXPLAIN 和 AVOID_EXECUTE 來顯示查詢計划,而不執行查詢。 |
Estimated # of Rows Returned: 7 | 估計該查詢返回 7 行。 |
Estimated Cost: 7 | 該估計成本值為 7,優化程序使用該值來比較不同查詢計划並選擇成本最低的查詢計划。 |
1) Informix.r: SEQUENTIAL SCAN | 將 cust_calls r 表用作外表並對它進行掃描以獲取每一行。 |
2) Informix.l: INDEX PATH | 對於外表中的每一行,請使用索引獲取內表 customer l 中的匹配行。 |
(1) Index Keys: customer_num (Serial, fragments: ALL) | 使用 customer_num 列的索引,對其進行連續掃描,並掃描所有的分段(customer l 表只有一個分段組成)。 |
Lower Index Filter: Informix.l.customer_num = Informix.r.customer_num | 從外表的 customer_num 值開始進行索引掃描。 |
NESTED LOOP JOIN | 采用嵌套循環連接方式 |
onmode -Y:動態更改 SET EXPLAIN
如果用戶沒有訪問 SQL 源代碼的權限,那么數據庫管理員可以通過使用運行 SQL 代碼的 onmode -Y 命令動態地設置 SET EXPLAIN 。對於單獨的會話,我們也可以使用 onmode -Y 命令動態更改 SET EXPLAIN 語句的值。
onmode -Y 命令基本語法:
調用 | 解釋 |
---|---|
onmode -Y sessionid 2 | 打開對 sessionid 的 SET EXPLAIN,並且僅顯示查詢計划 |
onmode -Y sessionid 1 | 打開對 sessionid 的 SET EXPLAIN |
onmode -Y sessionid 0 | 關閉對 sessionid 的 SET EXPLAIN |
當使用 onmode -Y 命令打開 SET EXPLAIN 時,輸出顯示在sqexplain.out.sessionid 文件中。
如果希望動態對 session 30 打開 SET EXPLAIN ON AVOID_Execute 特性,我們可以運行:
onmode – Y 30 2
如果希望動態對 session 30 打開 SET EXPLAIN ON 特性,我們可以運行:
onmode – Y 30 1
如果希望動態對 session 30 打開 SET EXPLAIN OFF 特性,我們可以運行:
onmode – Y 30 0
顯示查詢統計信息
在 Informix ONCONFIG 配置文件中的 EXPLAIN_STAT 配置參數用來控制是否在 sqexplain.out 文件中包含“查詢統計信息”。 如果啟用 EXPLAIN_STAT 配置參數,那么查詢統計信息部分將出現在 sqexplain.out 文件中。 sqexplain.out 文件中的“查詢統計信息”部分顯示了查詢計划預期返回的估計行數、返回的實際行數和查詢的其他信息。可以使用這些信息(顯示查詢計划綜合流量以及查詢的每個階段通過的行流量數)來調試性能問題。
EXPLAIN_STAT 配置參數可以設置為下列值:
值 | 描述 |
---|---|
0 | 禁用查詢統計信息的顯示 |
1 | 啟用查詢統計信息的顯示 |
我們也可以通過修改 onconfig 文件來修改此值,也可以通過 onmode – wf 及 onmode – wm 命令動態設置該值。
onmode – wf EXPLAIN_STAT= 1 onmode – wm EXPLAIN_STAT= 1
查詢統計信息只有在 SQL 語句執行之后才可以生成。當執行 set explain on 及 onmode – Y session_id 1 時,sqexplain.out 文件中會包含“查詢統計信息”。
以下示例顯示了 SET EXPLAIN 輸出中的查詢統計信息。如果已掃描或已連接的估計行數和實際行數相差很大,那么關於這些表的統計信息可能是舊的,應該更新它們。
select * from tab1, tab2 where tab1.c1 = tab2.c1 and tab1.c3 between 0 and 15 Estimated Cost: 104 Estimated # of Rows Returned: 69 1) zelaine.tab2: SEQUENTIAL SCAN 2) zelaine.tab1: INDEX PATH (1) Index Keys: c1 c3 (Serial, fragments: ALL) Lower Index Filter: (zelaine.tab1.c1 = zelaine.tab2.c1 AND zelaine.tab1.c3 >= 0 ) Upper Index Filter: zelaine.tab1.c3 <= 15 NESTED LOOP JOIN Query statistics: ----------------- Table map : ---------------------------- Internal name Table name ---------------------------- t1 tab2 t2 tab1 type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t1 50 50 50 00:00:00 4 type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t2 67 69 4 00:00:00 2 type rows_prod est_rows time est_cost ------------------------------------------------- nljoin 67 70 00:00:00 104
查詢計划樣例分析
下邊我們例舉一些查詢計划的樣例,希望能夠對查詢計划能夠有一個比較全面的了解。
單表查詢
下邊顯示了 customer 表上復雜查詢的 SET EXPLAIN 輸出:
QUERY: ------ SELECT fname, lname, company FROM customer WHERE company MATCHES 'Sport*' AND customer_num BETWEEN 110 AND 115 ORDER BY lname Estimated Cost: 1 Estimated # of Rows Returned: 1 Temporary Files Required For: Order By 1) virginia.customer: INDEX PATH Filters: virginia.customer.company MATCHES 'Sport*' (1) Index Keys: customer_num (Serial, fragments: ALL) Lower Index Filter: virginia.customer.customer_num >= 110 Upper Index Filter: virginia.customer.customer_num <= 115
以下輸出行顯示了該查詢的索引掃描的范圍:
- 以索引鍵值 110 開始索引掃描 :
Lower Index Filter: virginia.customer.customer_num >= 110
- 以索引鍵值 115 停止索引掃描 :
Upper Index Filter: virginia.customer.customer_num <= 115
多表查詢
下邊顯示了多表查詢的 SET EXPLAIN 輸出:
QUERY: ------ SELECT C.customer_num, O.order_num, SUM (I.total_price) FROM customer C, orders O, items I WHERE C.customer_num = O.customer_num AND O.order_num = I.order_num GROUP BY C.customer_num, O.order_num Estimated Cost: 78 Estimated # of Rows Returned: 1 Temporary Files Required For: Group By 1) virginia.o: SEQUENTIAL SCAN 2) virginia.c: INDEX PATH (1) Index Keys: customer_num (Key-Only) (Serial, fragments: ALL) Lower Index Filter: virginia.c.customer_num = virginia.o.customer_num NESTED LOOP JOIN 3) virginia.i: INDEX PATH (1) Index Keys: order_num (Serial, fragments: ALL) Lower Index Filter: virginia.o.order_num = virginia.i.order_num NESTED LOOP JOIN
SET EXPLAIN 輸出列出數據庫服務器訪問表的順序和讀取每個表的存取計划。上邊輸出的計划指示數據庫服務器將執行以下操作:
- 數據庫服務器將首先讀取orders表。
因為orders表上沒有過濾器,所以數據庫服務器必須讀取所有的行。按物理順序讀取表是成本最低的方法。
- 對於orders的每一行,數據庫服務器將在 customer 表中搜索匹配的行。
搜索使用customer_num的索引。標志僅鍵意味着對於 customer 表只需要讀取索引,因為只有c.customer_num列用在連接和輸出中且該列是索引鍵。
- 對於orders中具有一個匹配customer_num的每一行,數據庫服務器將使用order_num的索引在items表中搜索匹配行。
鍵優先掃描
鍵優先掃描是一種索引掃描,該掃描使用未列為低索引過濾器和高索引過濾器的鍵。下邊顯示了使用鍵優先掃描的樣本查詢:
select * from tab1 where (c1 > 0) and ( (c2 = 1) or (c2 = 2)) Estimated Cost: 4 Estimated # of Rows Returned: 1 1) pubs.tab1: INDEX PATH (1) Index Keys: c1 c2 (Key-First) (Serial, fragments: ALL) Lower Index Filter: pubs.tab1.c1 > 0 Index Key Filters: (pubs.tab1.c2 = 1 OR pubs.tab1.c2 = 2)
在此示例中數據庫服務器將首先通過應用附加的鍵過濾器嘗試減少可能的行數。數據庫服務器使用索引來應用附加的過濾器 c2 = 1 OR c2 = 2 之后才讀取行數據。
子查詢的查詢計划
如果連接的成本較低,那么優化程序可自動將子查詢更改成連接。下邊例子中的 SET EXPLAIN ON 語句的樣本輸出顯示了優化程序將子查詢中的表更改成連接中的內表:
QUERY: ------ SELECT company, fname, lname, phone FROM customer c WHERE EXISTS( SELECT customer_num FROM cust_calls u WHERE c.customer_num = u.customer_num) Estimated Cost: 6 Estimated # of Rows Returned: 7 1) virginia.c: SEQUENTIAL SCAN 2) virginia.u: INDEX PATH (First Row) (1) Index Keys: customer_num call_dtime (Key-Only) (Serial, fragments: ALL) Lower Index Filter: virginia.c.customer_num = virginia.u.customer_num NESTED LOOP JOIN (Semi Join)
當優化程序將子查詢更改成連接時,它可以使用存取計划和連接計划的幾種變形形式:
- 首行掃描
首行掃描是表掃描的一種變形形式。當數據庫服務器找到一個匹配時,表掃描將停止。
- 忽略副本索引掃描
忽略副本索引掃描是索引掃描的一種變形形式。數據庫服務器不掃描副本。
- 半連接
半連接是嵌套循環連接的一種變形形式。當第一個匹配找到時,數據庫服務器將停止內表掃描。
SQL 語句優化
通過對 SQL 語句查詢計划的分析,我們可以知道 SQL 語句在執行過程中是采用什么樣的訪問方法,是順序掃描還是索引掃描;表之間連接采用什么樣的方法,是嵌套循環連接還是哈希連接;表之間訪問的順序是什么;是否產生了臨時表;該查詢的成本是多少。依此,我們就可以考慮,為了提高 SQL 語句性能,我們是不是要創建合適的索引, 是不是要調整一下表之間連接的順序,是不是要修改一下 SQL 語句的寫法等。通常,我們在調整時,可以比較一下改變之前及改變之后的查詢成本,保證查詢成本有一個明顯的減少。另外,我們還可以通過設置 OPTCOMPIND 參數來指定數據訪問方法 ;通過訪問計划指示、連接次序指示、連接計划指示、目標指示來指定數據訪問方法、表連接順序、表連接方法及數據返回結果集;通過執行 update statistics 語句提高 SQL 語句性能。關於 OPTCOMPIND 參數及查詢指示的具體使用方法,請參考 Informix 信息中心相關內容。
SQL 下鑽查詢特性
在 SQL 語句性能監控時,我們經常要了解 SQL 語句執行了多長時間; SQL 語句運行時占用了多少系統資源,如 CPU 占用情況、內存占用情況、磁盤 I/O 讀寫情況; SQL 語句等待系統資源如磁盤 I/O 及鎖的時間及次數等。通過 SQL 語句對系統的資源使用及等待情況,我們可以了解到 SQL 語句運行的瓶頸,並及時調整系統資源配置,或者調整用戶的應用程序。我們上面介紹的 set explain 方法,可以幫助我們了解一些 SQL 語句性能問題,但是當我們啟用 SET EXPLAIN 功能時,SQL 語句性能可能已經出現了問題,為了能夠讓 DBA 更及時、更詳細地了解 SQL 語句的資源使用情況並做出相應的調整,在 Informix 中,提供了 SQL 下鑽查詢特性來滿足上述功能。
SQL 下鑽查詢特性可以收集關於系統上執行的每個 SQL 語句的統計信息,並分析語句歷史。它可以幫助您回答如下問題:
- SQL 語句需要多長時間
- 各個語句使用多少資源?
- 等待每個資源需要多長時間?
- 查詢計划是什么?
統計信息存儲在循環緩沖區(內存中名為 syssqltrace 的偽表)中,即存儲在 sysmaster 數據庫中。您可以動態地調整循環緩沖區的大小。
缺省情況下,該功能處於關閉狀態,但是您可以對所有用戶或一組特定用戶將其打開。在啟用帶有缺省配置的該功能時,數據庫服務器跟蹤運行的上 1000 條 SQL 語句以及這些語句的概要統計信息,每個 SQL 語句占用 1K 大小的空間。
如果您想要保存大量歷史信息,那么該功能需要的內存較大。 SQL 歷史跟蹤所需的缺省空間量為 1 兆字節。您可以根據需求增加或減少存儲量。如果不想要對此使用內存,那么可以禁用 SQL 歷史跟蹤。
使用 SQLTRACE 配置參數指定啟動 SQL 跟蹤信息
我們可以通過修改 $InformixDIR/etc/$ONCONFIG 文件中的 SQLTRACE 配置參數來控制數據庫服務器啟動時的缺省跟蹤行為。 所設置的信息包括要跟蹤的 SQL 語句數目和跟蹤方式。
SQLTRACE 配置參數語法:
SQLTRACE [Level=off|low|med|high], [Ntraces=number of traces], [Size=size of each trace buffer],[Mode=global|user]
其中:
level字段,可以指定以下某個值:
- Low:它用於捕獲語句統計信息、語句文本和語句迭代器。當啟用 SQL 跟蹤時,它是缺省的跟蹤級別。
- Medium:此跟蹤級別捕獲低級跟蹤中包含的所有信息,再加上表名、數據庫名稱和存儲過程堆棧。
- High:此跟蹤級別捕獲中級跟蹤中包含的所有信息,再加上主變量。
- Off:這不指定 SQL 跟蹤。系統缺省為 OFF
ntraces字段,指定要跟蹤的 SQL 語句的數目,其范圍是 : 500 -2147483647 。
size字段, 指定跟蹤緩沖區大小的千字節數。每個 SQL 語句的跟蹤信息使用一個跟蹤緩沖區,如果超過了此緩沖區大小,那么數據庫服務器丟棄已保存的數據。其范圍是 : 1K-100K 。
mode字段, 指定以下任意一項:
- Global:跟蹤系統上的所有用戶,它是缺省值。
- User:跟蹤指定用戶(如果想要獲取一小組用戶正在運行的 SQL 樣本,那么指定此項)。
在設置 SQLTRACE 參數時,我們需要考慮以下一些內容:
- 關於 SQLTRACE 緩沖區的問題:
我們收集到的統計信息都保存在內存的緩沖區中,它的大小 =Ntraces*Size,如果收集的語句數量越多、收集信息越詳細,需要的緩沖區就越大,占用的內存資源也就越多。因此,在配置時,要考慮自己的實際情況來選擇。另外,這個緩沖區是一個循環緩沖區,當緩沖區大小不夠時,它會將舊的信息丟掉,因此,如果需要保存 SQL 語句跟蹤歷史,要考慮它的大小問題。當我們將 SQL 跟蹤特性關閉時,保存在 SQLTRACE 緩沖區中的信息也會丟掉,如果需要保存,在關閉 SQL 跟蹤特性關閉前,請將這些信息保存到表或文件中,防止丟失。
- 關於 size 參數
size 參數的大小主要由 SQL 語句的大小及 Level 來決定。不同的 level,所收集的信息量不同,Medium 會比 low 收集的信息量大,同樣,High 會比 Medium 收集的信息量大。因此,在選擇時,要充分考慮好我們收集統計信息的用途。通常,Low Level 比較適合於錯誤診斷及性能調優,High Level 常用來做系統負載重現功能。 Medium Level 也主要用於一些錯誤診斷場合。
- 關於 Mode 參數
global 模式用於跟蹤系統上所有用戶的統計信息,因此,當在一個比較繁忙的系統上,可能很快就會收集到大量的信息,同時,所有用戶的信息都包含在一起,分析時也比較繁瑣,通常,選擇 global 模式,主要用於比較系統上所有會話的資源使用情況,或者是我們不清楚要分析哪一個具體用戶的資源使用情況。一般情況下,我們會使用 user 模式,這樣,我們分析起來會比較清晰,同時,占用的系統資源也不會太多。
以下語句指定了數據庫服務器將收集關於系統上所有用戶執行的最多 2000 條 SQL 語句的低級別信息,並將分配大約 4 兆字節的內存(2000 * 2 千字節)。
SQLTRACE level=LOW,ntraces=2000,size=2,mode=global
以下語句指定了數據庫服務器將收集關於系統上所有用戶執行的最多 2000 條 SQL 語句的高級別信息,並將分配大約 4 兆字節的內存(2000 * 2 千字節)。
SQLTRACE level=high,ntraces=2000,size=2,mode=global
使用 SQLTRACE 配置參數方式比較適合於設置一些缺省的配置,如果需要經常變化,使用 ADMIN API 命令方式則比較方便。
使用 ADMIN API 命令指定啟動 SQL 跟蹤信息
如果不想設置 SQLTRACE 配置參數以重新啟動服務器,那么可執行以下 ADMIN API 命令,該命令可提供與設置 SQLTRACE 相同的功能。使用 ADMIN API 的 task() and admin() 函數可以動態改變 SQLTRACE 的設置,不需要重新啟動服務器,使用更加靈活。只有 Informix 用戶有權力執行 ADMIN API 命令。通過 ADMIN API 命令修改的 SQLTRACE 的設置不會保存到 SQLTRACE 配置參數中,因此,當服務器重新啟動后,SQLTRACE 配置參數值將會生效。
當 SQLTRACE 配置參數為 OFF,我們通過下面的 ADMIN API 命令啟動 SQL 跟蹤信息時,系統會使用缺省的設置值。 即:
SQLTRACE level=low,ntraces=1000,size=1,mode=global
execute function task("set sql tracing on");
我們也可以指定自己設置的值。以下語句指定了數據庫服務器將收集關於系統上所有用戶執行的最多 2000 條 SQL 語句的低級別信息,並將分配大約 4 兆字節的內存(2000 * 2 千字節)。
execute function task("set sql tracing on", 2000,"2k","low","global");
停止收集 SQL 語句信息,我們可以執行:
execute function task("SET SQL TRACING OFF");
當執行上述命令后,會關閉 SQL 跟蹤功能,同時,跟蹤緩沖區中的內容會丟失。
啟用特定用戶的 SQL 歷史跟蹤
啟用特定用戶的 SQL 歷史跟蹤,不僅可以節省系統內存資源,而且分析起來也更加清晰,一般我們會建議采用這種方式。在以用戶方式啟用 SQL 跟蹤系統后,就可以啟用對特定用戶的跟蹤。在指定 user 作為 SQLTRACE 配置參數中的方式后,必須執行管理 API task() 或 admin() 函數來打開對特定用戶的 SQL 歷史跟蹤。
如果全局 SQL 跟蹤被禁用,那么可執行管理 API task() 或 admin() 函數來啟用對特定用戶的 SQL 跟蹤。
要啟用特定用戶的 SQL 歷史跟蹤,您可以執行 task 或 admin() 函數,並指定 set sql tracing on 和定義用戶的信息。
如果需要對 session 30 啟用 SQL 語句跟蹤,我們可以執行:
execute function task("set sql tracing on", 1000, 1,"low","user"); execute function task("set sql user tracing on",30)
如果需要對當前連接到系統的用戶(只要它們未作為用戶 root 或 Informix 登錄)啟用 SQL 語句跟蹤,我們可以執行:
dbaccess sysadmin -<<END execute function task("set sql tracing on", 1000, 1,"low","user"); select task("set sql user tracing on", sid) FROM sysmaster:syssessions WHERE username not in ("root","Informix"); END
如果需要停止對 session 30 進行跟蹤,我們可以執行:
execute function task( “ set sql user tracing off",30);
SQL 跟蹤信息顯示及分析
我們可以通過執行 onstat -g his 命令或查詢sysmaster數據庫中的 syssqltrace 偽表來獲取 SQL 下鑽查詢信息。
onstat – g his 命令
我們可以通過執行 onstat -g his 命令來顯示 SQL 下鑽查詢信息。
語法:
>>-onstat-- -g--his--------------------------------------------><
onstat -g his 選項顯示 SQLTRACE 收集到的信息並以格式化輸出。缺省情況下,只有 DBSA 可以查看 onstat -g his syssqltrace 信息。然而,當 UNSECURE_ONSTAT = 1 時,所有的用戶可以查看此信息。 onstat -g his 選項會將所收集到的所有信息全部顯示出來,目前還不能夠只顯示某一特定的用戶會話或 SQL 語句的信息。因此,它比較適合小數據量的顯示,它的好處是比較方便。
onstat -g his 選項的輸出主要包含三部分內容:trace profile, statement text and statement statistics.
Trace profile:這是 onstat -g his 命令輸出的前幾行信息,用於描述跟蹤的級別、跟蹤模式、跟蹤的 SQL 語句條數、跟蹤緩沖區的大小及跟蹤緩沖區保持的時間。如下所示:
onstat -g his 的輸出示例(Trace profile 部分):
Statement history: Trace Level High Trace Mode User Number of traces 50000 Current Stmt ID 3 Trace Buffer size 12264 Duration of buffer 37 Seconds Trace Flags 0x00007F21 Control Block 0x4b8cd018 ... ...
Statement text and iterators:onstat – g his 命令輸出的接下幾行用來描述被跟蹤的 SQL 語句以及查詢中用到的迭代器及查詢計划信息。 SQL 語句部分的內容根據跟蹤級別的不同而有所不同。如果跟蹤級別是 LOW,只是顯示被跟蹤的 SQL 語句及正在使用的數據庫的十六進制描述。如果蹤級別是 medium,將顯示數據庫的名稱,SQL 語句,SQL 語句中用到的表名稱及存儲過程的調用堆棧信息。如果跟蹤級別是 high,除了顯示 medium level 的信息外,還將顯示 SQL 語句中用到的宿主變量信息。如下所示:
onstat -g his 的輸出示例(Statement text and iterators: 部分):
... ... Statement # 3: @ 0x4b907018 Database: sysmaster Statement text: select first 2 substr(tabname,1,20) as table, isreads as reads from sysptprof where isreads > 10 order by isreads desc SELECT using tables [ systabnames sysptntab ] Iterator/Explain ================ ID Left Right Est Cost Est Rows Num Rows Partnum Type 3 0 0 9 33 40 20 Seq Scan 4 0 0 1 100 1 15 Index Scan 2 3 4 28 33 40 0 Nested Join 1 2 0 1 33 2 0 Sort 4 0 0 18 92 92 Disk Scan 2 3 4 287 1380 5060 Nested Join 1 2 0 1 1 5060 Insert ... ...
Statement information and statistics:接下來的部分主要包含 SQL 語句及性能統計信息,也是我們進行監控的最主要的部分。通過它,我們可以發現 SQL 語句相關的內存使用情況、磁盤 I/O 情況、鎖使用及爭用情況,CPU 使用情況,排序及索引使用情況等信息。據此,我們可以進行相應的調整。 我們又可以將其細化為下面三部分內容:
Statement information:描述下邊一些信息:
- 運行命令的用戶的用戶標識
- 數據庫會話標識
- 數據庫的名稱
- SQL 語句的類型
- SQL 語句執行的持續時間
- 該語句完成的時間
- 帶有語句類型的 SQL 語句文本或函數調用列表(也稱為堆棧跟蹤),例如: procedure1() calls procedure2() calls procedure3()
RSAM statistics:描述下邊一些信息:
- 緩沖區讀取和寫入的數目
- 頁面讀取和寫入的數目
- 排序和磁盤排序的數目
- 鎖請求和等待的數目
- 邏輯日志記錄的數目
SQL statistics:描述下邊一些信息:
- 估計的行數
- 優化器估計成本
- 返回的行數
- SQL/ISAM 錯誤
- 數據庫隔離級別
- SQL 語句內存使用量。
onstat -g his 的輸出示例(Statement information and statistics 部分):
... ... Statement information: Sess_id User_id Stmt Type Finish Time Run Time 26 501 SELECT 23:31:01 0.0054 Statement Statistics: Page Buffer Read Buffer Page Buffer Write Read Read % Cache IDX Read Write Write % Cache 0 410 100.00 0 0 0 0.00 Lock Lock LK Wait Log Num Disk Memory Requests Waits Time (S) Space Sorts Sorts Sorts 0 0 0.0000 0.000 B 1 0 1 Total Total Avg Max Avg I/O Wait Avg Rows Executions Time (S) Time (S) Time (S) IO Wait Time (S) Per Sec 1 0.0108 0.0108 0.0054 0.000000 0.000000 370.1291 Estimated Estimated Actual SQL ISAM Isolation SQL Cost Rows Rows Error Error Level Memory 28 33 2 0 0 CR 34176
輸出描述 :
- Page Read:已從磁盤讀取的頁數
- Buffer Reads: 從緩沖池讀取而不是從磁盤讀取頁面的次數
- Read % Cache: 應從緩沖池讀取頁面的次數的百分比
- Buffer IDX Read: 索引頁的緩沖區讀取數
- Page Write: 寫入磁盤的頁數
- Buffer Write:修改並發送回緩沖池的頁數
- Write % Cache:頁面寫入緩沖池而不是寫入磁盤的次數的百分比
- Lock Requests:該語句所需的鎖的總數
- Lock Waits:該 SQL 語句等待鎖的次數
- LK Wait Time:在該 SQL 語句執行期間,用於等待鎖的時間(以秒為單位)
- Log Space:
- Num Sorts:用於執行語句的排序總數
- Disk Sorts:對於該 SQL 語句,對磁盤執行的排序的次數
- Memory Sorts
- Total Executions:該語句已執行的總次數,或者該游標重用的次數
- Total Time:執行該語句的總時間(以秒為單位)
- Avg Time:執行該語句的平均時間(以秒為單位)
- Max Time:運行 SQL 語句的總時間(以秒為單位),不包括應用程序使用的任何時間
- LK Wait Time:語句等待應用程序鎖的時間量
- Avg IO Wait:語句等待 I/O 的時間量,不包括任何異步 I/O 。
- Avg Rows Per Sec:該語句每秒產生的平均行數
- Estimated Cost:與 SQL 語句關聯的代價
- Estimated Rows:返回的估計行數,由語句的優化程序估計
- Actual Rows:對於該語句返回的行數
- SQL Error:SQL 錯誤號
- ISAM Error:RSAM/ISAM 錯誤號
- Isolation Level:該語句運行時使用的隔離級別
- SQL Memory:該 SQL 語句需要的字節數
syssqltrace 偽表
在 Informix 中,提供了 3 張內存偽表用來保存 SQL 跟蹤信息。其中,syssqltrace 表用來提供被跟蹤的每一個 SQL 語句的詳細的跟蹤信息。它的大小由 ntraces*size 來決定。我們可以動態調整其大小。我們可以通過 sysmaster 數據庫來訪問這 3 張內存偽表。
syssqltrace 表的輸出信息同執行 onstat -g his 命令輸出的 Statement information and statistics 部分的內容相似。
由於我們可以使用 SQL 語句訪問 SQL 跟蹤信息,所以,采用該種方法比較適合查詢有關單個 SQL 語句或一組 SQL 語句的詳細跟蹤信息。
syssqltrace 表的基本結構如下:
列 | 類型 | 描述 |
---|---|---|
sql_id | int8 | 唯一 SQL 執行標識 |
sql_address | int8 | 代碼塊中的語句的地址 |
sql_sid | int | 運行 SQL 語句的用戶的數據庫會話標識 |
sql_uid | int | 運行 SQL 的語句的用戶標識 |
sql_stmttype | int | 語句類型 |
sql_stmtname | char(40) | 顯示為單詞的語句類型 |
sql_finishtime | int | 此語句的完成時間(UNIX) |
sql_begintxtime | int | 此事務的啟動時間 |
sql_runtime | float | 語句執行時間 |
sql_pgreads | int | 此 SQL 語句的磁盤讀取數 |
sql_bfreads | int | 此 SQL 語句的緩沖區讀取數 |
sql_rdcache | float | 從緩沖池讀取頁的時間百分比 |
sql_bfidxreads | int | 索引頁緩沖區讀取數 |
sql_pgwrites | int | 寫入磁盤的頁數 |
sql_bfwrites | int | 已修改並返回到緩沖池的頁數 |
sql_wrcache | float | 頁已寫入緩沖池,但未寫入磁盤的時間百分比 |
sql_lockreq | int | 此 SQL 語句所需鎖總數 |
sql_lockwaits | int | SQL 語句等待鎖的次數 |
sql_lockwttime | float | SQL 語句期間系統等待鎖定的時間 |
sql_logspace | int | 邏輯日志中 SQL 語句所用空間量 |
sql_sorttotal | int | 為語句運行的排序數 |
sql_sortdisk | int | 磁盤上運行的排序數 |
sql_sortmem | int | 內存中運行的排序數 |
sql_executions | int | SQL 語句運行的次數 |
sql_totaltime | float | 運行語句所用時間總量 |
sql_avgtime | float | 運行語句所用平均時間量 |
sql_maxtime | float | 執行 SQL 語句所用最大時間量 |
sql_numiowaits | int | I/O 操作必須等待的次數 |
sql_avgiowaits | float | SQL 語句必須等待的平均時間量 |
sql_totaliowaits | float | SQL 語句必須等待 I/O 的時間總量。這不包含任何異步 I/O 。 |
sql_rowspersec | float | 產生的平均行數(每秒) |
sql_estcost | int | 與 SQL 語句關聯的成本 |
sql_estrows | int | 按照優化器的預測為 SQL 語句返回的預估行數 |
sql_actualrows | int | 為 SQL 語句返回的行數 |
sql_sqlerror | int | SQL 錯誤號 |
sql_isamerror | int | RSAM/ISAM 錯誤號 |
sql_isollevel | int | SQL 語句的隔離級別。 |
sql_sqlmemory | int | 執行 SQL 語句所需字節數 |
sql_numiterators | int | 語句所用迭代器數 |
sql_database | char(128) | 數據庫名 |
sql_numtables | int | 執行 SQL 語句中所用表數 |
sql_tablelist | char(4096) | SQL 語句中直接引用的表名列表。如果 SQL 語句擊發對其他表執行語句的觸發器,將不列出其他這些表。 |
sql_statement | char(1600) | 已運行的 SQL 語句 |
如果我們要查看會話 30 的 SQL 跟蹤信息,可以執行:
select * from syssqltrace where sql_id =30;
syssqltrace_info 偽表
syssqltrace_info 偽表也是一張內存表,用來保存 tracing profile 信息。我們可以通過 sysmaster 數據庫來訪問這張內存偽表。 tracing profile 信息主要用於描述跟蹤的級別、跟蹤模式、跟蹤的 SQL 語句條數、跟蹤緩沖區的大小及跟蹤緩沖區保持的時間。
syssqltrace_info 偽表的輸出內容同執行 onstat -g his 命令輸出的 tracing profile 部分的內容相似。
syssqltrace_info 表的基本結構如下:
列 | 類型 | 描述 |
---|---|---|
flags | integer | SQL 跟蹤標志 |
ntraces | integer | 要跟蹤的項數 |
tracesize | integer | 為各 SQL 跟蹤項存儲的文本的大小 |
duration | integer | 跟蹤緩沖區(以秒為單位) |
sqlseen | int8 | 啟動或調整大小以來跟蹤的 SQL 項數 |
starttime | integer | 跟蹤的啟用時間 |
memoryused | int8 | SQL 跟蹤所用內存的字節數 |
syssqltrace_iter 偽表
syssqltrace_iter 偽表也是一張內存表,用來保存 Statement text and iterators 信息。我們可以通過 sysmaster 數據庫來訪問這張內存偽表。 Statement text and iterators 信息主要用來描述被跟蹤的 SQL 語句以及查詢中用到的迭代器及查詢計划信息。這個表常用來查詢特定 SQL 語句的查詢計划信息。
syssqltrace_iter 偽表的輸出內容同執行 onstat -g his 命令輸出的 Statement text and iterators 部分的內容相似。
syssqltrace_iter 表的基本結構如下:
列 | 類型 | 描述 |
---|---|---|
sql_id | int8 | SQL 執行標識 |
sql_address | int8 | SQL 語句塊的地址 |
sql_itr_address | int8 | 迭代器的地址 |
sql_itr_id | int | 迭代器標識 |
sql_itr_left | int | 向左的迭代器標識 |
sql_itr_right | int | 向右的迭代器標識 |
sql_itr_cost | int | 迭代器成本 |
sql_itr_estrows | int | 迭代器預估行數 |
sql_itr_numrows | int | 迭代器實際處理的行數 |
sql_itr_type | int | 迭代器類型 |
sql_itr_misc | int | 迭代器雜項標志 |
sql_it_info | char(256) | 顯示為文本的迭代器雜項標志 |
如果我們要查看 sql_id=15 的查詢所使用的迭代器及類型,我們可以執行:
select sql_itr_type, substr(sql_itr_info,1,20) as iterator_info, sql_itr_numrows from syssqltrace_iter where sql_id = 14;
通過執行 onstat -g his 命令或查詢sysmaster數據庫中的 syssqltrace 偽表,我們可以查看系統中運行的 SQL 語句、執行 SQL 所用的資源、運行 SQL 花費的時間、磁盤 / 頁面 / 緩沖區讀和寫的數量、使用的鎖數量、排序數量和使用的內存量。另外,還可以查看 Informix 優化器估計的運行 SQL 所要花費的時間。這樣,我們可以了解到 SQL 語句占用資源情況及存在的資源瓶頸,並進行相應的調整。另外,我們還可以對比 Informix 優化器估計的返回行數和實際的返回行數(sql_estrows 和 sql_actualrows)。如果這兩個數值差異很大,就說明 Informix 優化器並不掌握關於表中行和索引數量的正確的統計數據。這意味着需要運行 update statistics,從而向優化器提供正確的數據。
另外,通過查詢 syssqltrace 表,我們還可以發現系統中運行時間最長的 SQL 查詢、帶有太多表連接操作的查詢、不希望的連接類型、返回記錄太多的查詢、存在鎖等待的查詢等信息,以便於我們進行及時的調整及改進來提高 SQL 語句的性能。
如果我們要發現運行時間最長的 SQL 查詢,我們可以執行:
select first 5 substr(sql_statement,1,50) as statement , sql_avgtime as Average_Time , sql_executions as Number_of_times from syssqltrace order by sql_avgtime desc ;
如果我們要發現返回記錄太多的查詢,我們可以執行:
select first 5 sql_estrows as est_rows , sql_actualrows as actual_rows , substr(sql_statement,1,30) as statement from syssqltrace order by sql_actualrows desc ;
結論
本文主要給大家介紹了 Informix 數據庫對 SQL 語句性能監控的兩種基本的方法及使用,關於 SQL 語句調優的相應方法及建議,大家可以參考 Informix 信息中心中性能調整部分。