Hibernate r_组4_(成本=0.00..8.28行=1宽度=8)(实际时间=0.023..0.023行=1圈=6) 索引条件:(组4_u2;id=15499) 筛选器:(未删除组4) 总运行时间:652504.827毫秒 (29排)
我正在阅读论坛帖子和用户手册,但我不知道是什么让它运行得更快,除非有可能为使用Hibernate r_组4_(成本=0.00..8.28行=1宽度=8)(实际时间=0.023..0.023行=1圈=6) 索引条件:(组4_u2;id=15499) 筛选器:(未删除组4) 总运行时间:652504.827毫秒 (29排),hibernate,sql,postgresql,indexing,postgresql-9.0,Hibernate,Sql,Postgresql,Indexing,Postgresql 9.0,我正在阅读论坛帖子和用户手册,但我不知道是什么让它运行得更快,除非有可能为使用now()函数的select创建索引。我重写了您的查询,并假设这会更快: SELECT u.id AS id14_, u.first_name AS first2_14_, u.last_name AS last3_14_, u.street_1 AS street4_14_, u.street_2 AS street5_14_, u.city AS city14_, u.us_state_id AS us7_14_,
now()
函数的select创建索引。我重写了您的查询,并假设这会更快:
SELECT u.id AS id14_, u.first_name AS first2_14_, u.last_name AS last3_14_, u.street_1 AS street4_14_, u.street_2 AS street5_14_, u.city AS city14_, u.us_state_id AS us7_14_, u.region AS region14_, u.country_id AS country9_14_, u.postal_code AS postal10_14_, u.user_name AS user11_14_, u.password AS password14_, u.profession AS profession14_, u.phone AS phone14_, u.url AS url14_, u.bio AS bio14_, u.last_login AS last17_14_, u.status AS status14_, u.birthdate AS birthdate14_, u.ageinyears AS ageinyears14_, u.deleted AS deleted14_, u.createdate AS createdate14_, u.audit AS audit14_, u.migrated2008 AS migrated24_14_, u.creator AS creator14_
FROM dir_users u
WHERE u.status = 'active'
AND u.deleted = FALSE
AND EXISTS (
SELECT 1
FROM dir_memberships m
JOIN dir_roles r ON r.id = m.role
JOIN dir_groups g ON g.id = m.group_id
WHERE m.group_id = 15499
AND m.user_id = u.id
AND (m.expires IS NULL
OR m.expires > now() AND (m.startdate IS NULL OR m.startdate < now()))
AND m.deleted = FALSE
AND r.deleted = FALSE
AND r.name = 'ROLE_MEMBER'
AND g.deleted = FALSE
)
AND EXISTS (
SELECT 1
FROM dir_memberships m
JOIN dir_roles r ON r.id = m.role
WHERE (m.expires IS NULL
OR m.expires > now() AND (m.startDate IS NULL OR m.startDate < now()))
AND m.deleted = FALSE
AND m.user_id = u.id
AND r.name = 'ROLE_TEACHER_MEMBER'
)
WHERE
条件必须与您的查询相匹配,索引才有用
我假设您已经在相关外键上拥有主键和索引
进一步:
CREATE INDEX dir_memberships_u_id_role_idx ON dir_memberships (user_id, role)
WHERE deleted = FALSE;
为什么要第二次user\u id
?。见:
user\u id
已在另一个索引中使用,因此您不会阻止它(这只能用于任何索引中未涉及的列)
为什么角色?
我假设两列的类型都是integer
(4字节)。我在您的详细问题中看到,您运行的64位操作系统包含8个字节,因此另一个整数根本不会使索引增长。我加入了role
,这可能对第二个EXISTS
半联接有用
如果您有许多“死亡”用户,这也可能会有所帮助:
CREATE INDEX dir_users_id_idx ON dir_users (id)
WHERE status = 'active' AND deleted = FALSE;
像往常一样,检查EXPLAIN
以查看索引是否被实际使用。您不会希望无用的索引占用资源
我们快了吗
当然,所有的常用建议也适用。查询,减去最后4个条件,即
and group4_.deleted=false
and user1_.STATUS='active'
and user1_.deleted=false
and (membership0_.USER_ID in (...))
返回758行。这758行中的每一行都将通过select membership7.USER\u ID…
子查询,运行时间为843.967毫秒
843.967*758=639726.986,接下来是10分钟
至于优化查询,我认为您不需要在子查询中使用DIR\u USERS user8\
。您可以先删除它,然后将子查询更改为使用EXISTS
,而不是中的
顺便问一下,数据库是否正在清空?即使没有任何调整,查询看起来也没有那么复杂或需要10分钟的数据量。您的表上目前有哪些索引?您可能会对自动清空感兴趣。奇怪的case
表达式在ORM计算字段中相当典型。Wow!感谢@Erwin所做的所有工作。我还没有考虑过重写查询,因为它是由hibernate自动生成的。如果需要,可以在我的应用程序中下拉到sql,但如果更好的索引或清空有帮助,我认为这将是一个更好的解决方案。此外,我还考虑过添加一个新索引,但postgres不允许索引xes中的函数与now()类似(“错误:索引谓词中的函数必须标记为不可变”)。否则,我认为dir_memberships__id_role_idx会有所帮助。@Atrutt:噢,我这方面的疏忽太多了。当然,你不能使用now()
在索引条件中。我删除了该条件,使索引效率降低,但可能仍然有用。我有一个类似的设置,每天使用当前日期而不是现在()重新创建索引。要使用此设置,您必须向查询中添加匹配的表达式(除了使用now()的确切条件)
。这非常有效,但需要一些开销。在相关表上运行真空完全分析
后,您的查询是否仍然很慢?可能足以修复自动真空。@atrutt:感谢反馈。这将显示ORMs butcher的性能如何。对于更复杂的查询,它们是粗糙的拐杖。我在pg_stat中查找了它它的数据库从来没有被清空过。你可能对它感兴趣。它在PostgreSQL的现代版本中是默认的。@ AtRuTu: PostgreSQL 9应该自动地进行抽真空。但是你可能需要考虑到一个更新到90.8。自从90.0以来,有几个关于真空的修复(你的版本)。是的,我们验证了autovacuum守护进程正在运行,并且已经清空了一些表。
CREATE INDEX dir_memberships_u_id_role_idx ON dir_memberships (user_id, role)
WHERE deleted = FALSE;
CREATE INDEX dir_users_id_idx ON dir_users (id)
WHERE status = 'active' AND deleted = FALSE;
and group4_.deleted=false
and user1_.STATUS='active'
and user1_.deleted=false
and (membership0_.USER_ID in (...))