2011-08-02 38 views
1

測試用例:H2優化select語句/關機碎片整理

drop table master; 
create table master(id int primary key, fk1 int, fk2 int, fk3 int, dataS varchar(255), data1 int, data2 int, data3 int, data4 int,data5 int,data6 int,data7 int,data8 int,data9 int,b1 boolean,b2 boolean,b3 boolean,b4 boolean,b5 boolean,b6 boolean,b7 boolean,b8 boolean,b9 boolean,b10 boolean,b11 boolean,b12 boolean,b13 boolean,b14 boolean,b15 boolean,b16 boolean,b17 boolean,b18 boolean,b19 boolean,b20 boolean,b21 boolean,b22 boolean,b23 boolean,b24 boolean,b25 boolean,b26 boolean,b27 boolean,b28 boolean,b29 boolean,b30 boolean,b31 boolean,b32 boolean,b33 boolean,b34 boolean,b35 boolean,b36 boolean,b37 boolean,b38 boolean,b39 boolean,b40 boolean,b41 boolean,b42 boolean,b43 boolean,b44 boolean,b45 boolean,b46 boolean,b47 boolean,b48 boolean,b49 boolean,b50 boolean); 

create index idx_comp on master(fk1,fk2,fk3); 
@loop 5000000 insert into master values(?, mod(?,100), mod(?,5), ?,'Hello World Hello World Hello World',?, ?, ?,?, ?, ?, ?, ?, ?,true,true,true,true,true,true,false,false,false,true,true,true,true,true,true,true,false,false,false,true,true,true,true,true,true,true,false,false,false,true,true,true,true,true,true,true,false,false,false,true,true,true,true,true,true,true,false,false,false,true); 

1.以下select語句需要長達30秒。有沒有優化響應時間的方法?

SELECT count(*), SUM(CONVERT(b1,INT)) ,SUM(CONVERT(b2,INT)),SUM(CONVERT(b3,INT)),SUM(CONVERT(b4,INT)),SUM(CONVERT(b5,INT)),SUM(CONVERT(b6,INT)),SUM(CONVERT(b7,INT)),SUM(CONVERT(b8,INT)),SUM(CONVERT(b9,INT)),SUM(CONVERT(b10,INT)),SUM(CONVERT(b11,INT)),SUM(CONVERT(b12,INT)),SUM(CONVERT(b13,INT)),SUM(CONVERT(b14,INT)),SUM(CONVERT(b15,INT)),SUM(CONVERT(b16,INT)) 
FROM master 
WHERE fk1=53 AND fk2=3 

2.I嘗試關閉碎片整理。但是這個說法花了我的測試案例約40分鐘。關閉碎片整理後,選擇最多需要15秒。如果我再次執行語句,則需要1秒。即使停止並啓動服務器,該語句也需要大約1秒。 H2是持久性緩存嗎?

基礎設施:web瀏覽器< - > H2控制檯服務器< - > H2 DB:H2 1.3.158

+0

查詢掃描有多少行?它看起來像是50000(不確定)。 –

+0

SELECT COUNT(*), SUM(CONVERT(B1,整數)), SUM(CONVERT(B16,INTEGER)) FROM PUBLIC.MASTER /* PUBLIC.IDX_COMP:FK1 = 53 AND FK2 = 3 */ /* scanCount:50001 */ WHERE(FK1 = 53) AND(FK2 = 3) /*總 :55199 MASTER.IDX_COMP讀:481(0%) MASTER.MASTER_DATA讀:54718(99%) */ (1 Datensatz,27368 ms) – Peter

回答

2

根據探查器輸出,主要問題(93%)是從磁盤讀取。我在H2控制檯運行此:

@prof_start; 
SELECT ... FROM master WHERE fk1=53 AND fk2=3; 
@prof_stop; 

,並得到:

Profiler: top 3 stack trace(s) of 48039 ms [build-158]: 
4084/4376 (93%): 
at java.io.RandomAccessFile.readBytes(Native Method) 
at java.io.RandomAccessFile.read(RandomAccessFile.java:338) 
at java.io.RandomAccessFile.readFully(RandomAccessFile.java:397) 
at org.h2.store.FileStore.readFully(FileStore.java:285) 
at org.h2.store.PageStore.readPage(PageStore.java:1253) 
at org.h2.store.PageStore.getPage(PageStore.java:707) 
at org.h2.index.PageDataIndex.getPage(PageDataIndex.java:225) 
at org.h2.index.PageDataNode.getRowWithKey(PageDataNode.java:269) 
at org.h2.index.PageDataNode.getRowWithKey(PageDataNode.java:270) 

根據EXPLAIN ANALYZE SELECT它的讀數超過55'000頁從磁盤(2 KB每一頁; 110 MB)此查詢。我不確定其他數據庫如何執行這樣的查詢。但我猜如果可能的話應該改變查詢,以便它讀取更少的數據。

+1

爲什麼在我的測試用例中關閉碎片整理這麼慢?爲什麼在重新啓動服務器後速度很慢? – Peter

1

是否有可能有一個臨時表/視圖已經做了數據類型轉換?如果偶爾從主表更新自己(一晚上有一次)是可行的,那麼您已經有很多處理能力進入已經完成的轉換。

如果這樣做不可行,您可能需要執行多個子選擇,每個「b」列一個,其中您只需拉動b#= 1。然後執行COUNT而不是SUM,這應該更快好。例如:

SELECT (count1+count2) AS Count, 
(SELECT COUNT(*) FROM master WHERE fk1=53 AND fk2=3 AND b1=1) AS count1 
(SELECT COUNT(*) FROM master WHERE fk1=53 AND fk2=3 AND b2=1) AS count2 

我不知道這確切的語法在你的程序工作,但希望作爲一個通用的SQL知道它可以讓你在正確的軌道上。

+0

我跟着你的第一個su通過在我的測試用例中用tinyint替換布爾值來獲取通道。 SELECT語句看起來像SELECT count(*),SUM(b1)... SUM(b16) 現在,語句花費的時間甚至更長。 – Peter

+0

甚至SELECT COUNT(*)FROM master WHERE fk1 = 93 AND fk2 = 3 AND b2 = 1最多需要15秒。數據庫越大(tinyint>布爾值),響應時間越差。 – Peter

+0

這對於總共50k行是很慢的(如果我正確理解了上面的註釋 - 是每個子查詢50k還是總共50k?)。事實上,你有三列索引*可能*有助於這一點。您將所有三個索引編制爲一個索引的原因是什麼?看起來fk3在你最麻煩的查詢中甚至沒有出現,這讓我想知道爲什麼要麻煩索引它,更不用說它是作爲一個複合索引添加的。 – roberttdev