1

测试用例:

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.我试过关机碎片整理。但是对于我的测试用例来说,这个语句大约需要 40 分钟。关闭碎片整理后,选择最多需要 15 秒。如果我再次执行该语句,则需要不到 1 秒。即使停止和启动服务器,该语句也需要大约 1 秒。H2 有持久缓存吗?

基础设施:WebBrowser <-> H2 控制台服务器 <-> H2 DB:h2 1.3.158

4

2 回答 2

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)用于此查询。我不确定其他数据库如何执行此类查询。但我想如果可能的话,应该更改查询,以便读取更少的数据。

于 2011-08-02T19:16:38.537 回答
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 想法,它能让您走上正确的轨道。

于 2011-08-02T12:40:55.163 回答