2016-03-08 132 views
1

我有一個Informix中的11即使適當的索引存在運行速度慢一個非常簡單的查詢,它正在使用:慢的Informix COUNT/GROUP BY查詢,即使有合適的索引

select COUNTRY, COUNT(*) from EVENTS group by COUNTRY 

有什麼爲什麼它應該運行緩慢?我有使用SQL Server進行類似查詢的經驗,如果存在適當的索引,他們會立即執行。

的更多信息:

  • 查詢花費500.000記錄15秒左右的活動表(讓我擔心,因爲這個表將有上百萬的記錄,我已經看到,執行時間正在迅速增加)。
  • EVENTS表按國家/地區列出索引。通過使用EXPLAIN指令,我檢查了這個索引正在被使用。
  • EVENTS表有許多列(約70)。
  • 「country」列是varchar(32)。
  • 「國家」有25個不同的值。
  • 表掃描是通過Informix的完成:

 
1) informix.EVENTS: INDEX PATH

(1) Index Name: informix.country_ix Index Keys: COUNTRY (Serial, fragments: ALL) Query statistics: ----------------- Table map : ---------------------------- Internal name Table name ---------------------------- t1 EVENTS type table rows_prod est_rows rows_scan time est_cost ------------------------------------------------------------------- scan t1 501906 39285 501906 00:14.88 29390 type rows_prod est_rows rows_cons time est_cost ------------------------------------------------------------ group 25 4 501906 00:15.58 79761

+0

您使用的是11.10,11.50還是11.70版本?你有沒有運行UPDATE STATISTICS?沒有運行的問題比過去的版本(例如12.10)要多得多,但仍然值得檢查。你在哪個平臺上運行?事件表中的一行有多大? –

+0

它仍然需要閱讀所有索引頁面才能計算每個COUNTRY的事件數量。 –

+0

我的Informix版本是在Linux(Ubuntu)中運行的11.70.UC4D。我更新了統計數據,但沒有任何區別。然而(正如我在下面告訴洛倫佐)刪除索引(並強制連續掃描),查詢執行得更快,這讓我感到驚訝。我會嘗試計算行大小。作爲第一個近似值,它可能是每行大約1kB。 –

回答

2

所以,我做了一些測試。

TL; DR

  • 改國號列類型CHAR(32),重建索引,你應該有更好的性能。

長的版本:

二手的Informix 12.10FC6DE在Linux CentOS的7(VM在VirtualBox中創建)。用於dbspace的頁面大小爲2048字節,緩衝池爲50000頁。

創建一個表格(tst),行大小約爲425字節(每頁平均4行),幷包含多列。其中一列是country VARCHAR(32),另一列是static_country CHAR(32)。 用499999行填充表格,其中列表countrystatic_country均勻分佈爲25個國家/地區名稱。

創建了2個索引,其中一列在列country(idx1_tst)和其他列static_country(idx2_tst)上。

表分區使用了125000個數據頁(使用oncheck -pT)。 索引大約有1500頁(使用oncheck -pT)。

A.運行查詢多次,迫使序列完備SCAN(運行時間分別爲10和15秒之間):

SELECT --+ FULL (tst) 
    country, COUNT(*) 
FROM 
    tst 
GROUP BY 
    country 

DIRECTIVES FOLLOWED: 
FULL (tst) 
DIRECTIVES NOT FOLLOWED: 

Estimated Cost: 1415645 
Estimated # of Rows Returned: 25 
Temporary Files Required For: Group By 

    1) mydb.tst: SEQUENTIAL SCAN 


Query statistics: 
----------------- 

    Table map : 
    ---------------------------- 
    Internal name  Table name 
    ---------------------------- 
    t1    tst 

    type  table rows_prod est_rows rows_scan time  est_cost 
    ------------------------------------------------------------------- 
    scan  t1  499999  499999 499999  00:12.17 140001 

    type  rows_prod est_rows rows_cons time  est_cost 
    ------------------------------------------------------------ 
    group 25   25  499999  00:13.01 1275644 

B.運行查詢多次,迫使索引掃描在country列索引,它的類型的VARCHAR(32)(4m30s和5m之間的運行時間):

SELECT --+ INDEX (tst idx1_tst) 
    country, COUNT(*) 
FROM 
    tst 
GROUP BY 
    country 

DIRECTIVES FOLLOWED: 
INDEX (tst idx1_tst) 
DIRECTIVES NOT FOLLOWED: 

Estimated Cost: 3462411 
Estimated # of Rows Returned: 25 

    1) mydb.tst: INDEX PATH 

    (1) Index Name: mydb.idx1_tst 
     Index Keys: country (Serial, fragments: ALL) 


Query statistics: 
----------------- 

    Table map : 
    ---------------------------- 
    Internal name  Table name 
    ---------------------------- 
    t1    tst 

    type  table rows_prod est_rows rows_scan time  est_cost 
    ------------------------------------------------------------------- 
    scan  t1  499999  499999 499999  04:49.71 3462411 

    type  rows_prod est_rows rows_cons time  est_cost 
    ------------------------------------------------------------ 
    group 25   25  499999  04:50.51 1275644 

C.運行查詢幾次,迫使一個索引掃描的static_country列索引,它的類型CHAR(32)的(2和3秒之間的運行時間):

SELECT --+ INDEX (tst idx2_tst) 
    static_country, COUNT(*) 
FROM 
    tst 
GROUP BY 
    static_country 

DIRECTIVES FOLLOWED: 
INDEX (tst idx2_tst) 
DIRECTIVES NOT FOLLOWED: 

Estimated Cost: 16428 
Estimated # of Rows Returned: 25 

    1) mydb.tst: INDEX PATH 

    (1) Index Name: mydb.idx2_tst 
     Index Keys: static_country (Key-Only) (Serial, fragments: ALL) 


Query statistics: 
----------------- 

    Table map : 
    ---------------------------- 
    Internal name  Table name 
    ---------------------------- 
    t1    tst 

    type  table rows_prod est_rows rows_scan time  est_cost 
    ------------------------------------------------------------------- 
    scan  t1  499999  499999 499999  00:02.02 16429 

    type  rows_prod est_rows rows_cons time  est_cost 
    ------------------------------------------------------------ 
    group 25   25  499999  00:02.72 1277132 

上的sysmaster使用SMI表sysptprof數據庫我可以看到以下計數器(使用運行之間onstat -z重置計數器):

  1. 在情況A(序列完備SCAN):
    • 表TST分區:
      • lockreqs 499999
      • isreads 125001
      • bufreads 500060
      • pagreads 117532
  2. 在情況B(在VARCHAR類型列INDEX SCAN):
    • 表TST分區:
      • lockreqs 499999
      • isreads 499990
      • bufreads 999997
      • pagreads 348585
    • 指數idx1_tst分區:
      • lockreqs 499999
      • isreads 500009
      • bufreads 506961
      • pagreads 2545
  3. 在情況C(在CHAR型柱INDEX SCAN):
    • 指數idx2_tst分區:
      • lockreqs 499999
      • isreads 500000
      • bufreads 502879
      • pagreads 1440

因此,對於序列完備SCAN只有對錶分區活動,如我所料。

對於CHAR列上的INDEX SCAN,索引分區上只有活動,正如我預期的那樣(解釋包含Key-Only指示)。

對於VARCHAR colum上的INDEX SCAN,表和索引分區都有活動,而不是我所期望的(但正如費爾南多所指出的,解釋不包含Key-Only指示)。

我無法從informix解釋這種行爲。但是,一個同事向我指出的Informix的性能手冊此條目(版本12.10FC6,第10章,查詢計劃,訪問計劃):

重要:優化器不會選擇僅鍵掃描一VARCHAR 列。如果要利用僅鍵掃描,請使用帶有MODIFY子句的ALTER TABLE將列更改爲CHAR數據類型。

+0

非常感謝你的徹底調查和你的詳細解釋,路易斯。我從VARCHAR更改爲CHAR,現在查詢執行得很快(250,000條記錄爲400毫秒,500,000爲500毫秒,1,000,000爲800毫秒)。現在我的sqexplain說只有鑰匙。用COUNT(1)替換COUNT(*)沒有區別。 –

1

事我會嘗試:

  • COUNT(1)而不是COUNT(*)的情況下,數據庫管理系統是愚蠢的
  • 測試查詢和檢查沒有索引的執行計劃,因爲我牛逼可能是混亂
  • 源檢測一下了查詢索引速度和嘗試不同的索引類型
+0

謝謝你的提示,洛倫佐。使用'COUNT(country)'或'COUNT(1)'沒有區別。但是,除去索引(Informix從INDEX PATH更改爲SEQUENTIAL SCAN),查詢執行得更快(5秒而不是15)。我想知道爲什麼!我想不出任何其他指數(與我擁有的不同:單列「國家」)。 –

+0

查看其他選項的查詢計劃會很有趣。 今天我在類似的查詢中看到了這個「eefect」。值得注意的是,查詢計劃沒有提及「僅鍵」,並且這與完美匹配答案並驗證數據分區正在被訪問。 使用COUNT(1)應該消除這種影響。 –

相關問題