【发布时间】:2014-12-29 21:51:42
【问题描述】:
我在嵌入式 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,用于构建应用程序文件夹树。当用户开始展开树时,我会加载有关文件和相关 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:h2://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 个 Int(每个字符串有 10 个逗号分隔的随机 Int 值)。
【问题讨论】:
标签: performance resultset h2