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 (...))