H2加入大表时的查询性能

时间:2014-12-29 21:51:43

标签: performance resultset h2

我在嵌入式H2数据库中有以下表格:

ACE (1,655,953) | PARENT_CHILD (4,544,788) | FILE (328,584)
-------------------------------------------------------------
ID              | ID                       | ID
MEMBER_ID       | PARENT_FILE_ID           | NAME
FILE_ID         | CHILD_FILE_ID            |
  • ACE是FILE的访问控制条目,具有FILE表的外键和MEMBER_ID上的索引
  • PARENT_CHILD保存文件及其所有父项(不仅仅是直接父项)之间的关系。它有两个FILE表的外键。
  • FILE保存有关文件的信息

应用程序在树中为选定成员显示文件/ ace信息。我需要PARENT_CHILD表来支持应用程序树中的延迟加载。我没有在内存中加载所有ace /文件信息,但我只查询适用的文件ID。当找到与深层嵌套文件匹配时,加入PARENT_CHILD表会给我所有父项(树必须知道哪些根元素属于匹配文件)。我在内存中保存了一个文件ID数组,用于构建应用程序文件夹Tree。当用户开始展开树时,我会加载有关该文件和相关ACE的其他信息。我不想显示内容中没有任何匹配ACE的文件夹。但是,如果深层嵌套文件夹/文件有匹配,我需要在树中呈现完整路径。

所以我使用这个查询:

select distinct parent_file_id from parent_child 
inner join ace on parent_child.child_file_id = ace.file_id 
where ace.member_id = 1;

这对于拥有大约40,000个匹配ACE的成员非常有效,但是当成员有多个匹配时,此查询开始执行非常糟糕(20秒)。我测试使用Squirrel(1536 MB java内存,Xmx)和以下连接字符串(缓存大小768MB):

JDBC:H 2:// C:\ H2DB; CACHE_SIZE = 786432; query_cache_size变量= 0;

执行计划如下:

SELECT DISTINCT
PARENT_CHILD.PARENT_ID
FROM ACE
/* ACE_MEMBER_ID_FK_INDEX_E: MEMBER_ID = 1 */
/* WHERE ACE.MEMBER_ID = 1
*/
/* scanCount: 456397 */
INNER JOIN PARENT_CHILD
/* PARENT_CHILD_FILE_ID_FILE_ID_FK_INDEX_E: CHILD_FILE_ID = ACE.FILE_ID */
/* scanCount: 6969581 */
WHERE (ACLITEM.MEMBER_ID = 1)
AND (PARENTFILE.FILE_ID = ACLITEM.FILE_ID)
/*
reads: 840206
*/

结果数:328,584。我假设磁盘上的某个临时文件导致性能下降,因为与PARENT_CHILD的连接正在生成许多记录。我已经将MAX_MEMORY_ROWS增加到10,000,000,这使得查询在20而不是40秒内执行。

有关如何改进此查询的任何想法?

成员ID上的子查询需要2.6秒才能完成(没有'读取结果'时间,456,396条记录)。这听起来对我来说也很长,因为它只是对索引的查询:

select * from ACE where member_id = 1;

也许我必须重新考虑应用程序树的延迟加载机制与文件夹/文件。问题是,在我可以渲染树的根元素之前,我需要知道是否存在匹配的子文件。我不想显示没有为所选用户提供任何匹配内容的文件夹。

感谢。

编辑:也许我只会将所有父ID在fILE记录中以逗号分隔的字符串存储。然后我不需要PARENT_CHILD表,在我的Java应用程序中,只需要0.8秒就可以将500,000个字符串分成5,000,000个Ints(每个字符串有10个逗号分隔的随机Int值)。

1 个答案:

答案 0 :(得分:0)

parent_child(child_file_id)上没有可用的索引。这意味着连接操作需要parent_child的全表扫描。 执行计划似乎是合理的,但无论如何,它需要嵌套循环加入450000 x 7毫升行。这很慢。 您应该在parent_child(child_file_id)上创建索引,或者切换到能够使用哈希联接的DBMS。