Performance H2连接大表时的查询性能
我在嵌入式H2数据库中有以下表格:Performance H2连接大表时的查询性能,performance,resultset,h2,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
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是文件的访问控制项,具有文件表的外键和成员ID上的索引
- PARENT_CHILD保持文件与其所有父级(而不仅仅是直接父级)之间的关系。它有两个指向文件表的外键
- 文件保存有关文件的信息
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;
这对于有大约40000个匹配ACE的成员来说非常有效,但是当一个成员有很多匹配项时,这个查询开始执行得非常糟糕(20秒)。我使用Squirrel(1536mbjava内存,Xmx)和以下连接字符串(缓存大小768MB)进行测试:
jdbc:h2://C:\H2DB;缓存大小=786432;查询\缓存\大小=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
*/
结果数:328584。我假设磁盘上的某个临时文件导致了性能下降,因为与父/子连接会生成许多记录。我已经将MAX_MEMORY_行增加到10000000,这使得查询的执行时间从40秒缩短到了20秒
关于如何改进这个查询有什么想法吗
对成员id的子查询需要2.6秒才能完成(如果没有“读取结果”时间,则为456396条记录)。对我来说这听起来也很长,因为这只是对索引的查询:
select * from ACE where member_id = 1;
也许我必须重新考虑应用程序树中文件夹/文件的延迟加载机制。问题是,在渲染树的根元素之前,我需要知道是否有匹配的子文件。我不想显示所选用户没有任何匹配内容的文件夹
谢谢
编辑:也许我只是将所有父id作为逗号分隔的字符串存储在文件记录中。然后我不需要表PARENT\u CHILD,在我的Java应用程序中,将500000个字符串拆分为5000000个Int(每个字符串有10个逗号分隔的随机Int值)只需0.8秒。在PARENT\u CHILD(CHILD\u file\u id)上没有可用的索引。这意味着联接操作需要对父项和子项进行完整的表扫描。 执行计划似乎是合理的,但无论如何,嵌套循环需要连接450000x7mln行。它很慢。
您应该在父项子项(子项文件id)上创建一个索引,或者切换到能够进行哈希联接的DBMS。列父项子项(子项文件id)是文件表的外键,因此自动成为索引,对吗?您可以看到,成员id是非选择性的—大约是表大小的1/4。然后,您有400000个索引扫描到父/子表中。鉴于父/子表很大,系统不善于在没有任何预测顺序的情况下兑现如此大规模的访问。一种可能的解决方案是尝试从父/子表和ace中删除id,并分别在(成员id、文件id)和(子/文件id、父/文件id)上生成主键。这应该为两个表(聚集索引)提供适合缓存上述查询的顺序。但无论如何,最好的解决方案是完全重新设计表结构——这都是关于用关系代数表示的层次结构。有几种方法可以做到这一点。比如读一下这个,