为连接查询的视图建立索引?

发布于 2024-12-27 10:06:04 字数 2916 浏览 2 评论 0原文

我有一个 SELECT 语句,它从一个更复杂的视图中进行一个非常简单的查询:

我有一个相当直接的 select 语句:

SELECT uid
FROM   userpermissions
WHERE  uid         = :whoami
AND    application = :application
AND    subsystem   = :subsystem
;

我的视图只有 ints 和 varchars,但是四个表的联接(可能是真正的问题)。

                       View "public.userpermissions"
   Column    |          Type          | Modifiers | Storage  | Description
-------------+------------------------+-----------+----------+-------------
 uid         | integer                |           | plain    |
 gid         | integer                |           | plain    |
 sid         | integer                |           | plain    |
 name        | character varying(128) |           | extended |
 application | character varying(128) |           | extended |
 subsystem   | character varying(128) |           | extended |
View definition:
 SELECT users.uid, groups.gid, groupaccess.sid, groups.name, subsystems.application, subsystems.subsystem
   FROM users
   JOIN groups ON groups.gid = users.gid
   JOIN groupaccess ON groups.gid = groupaccess.gid
   JOIN subsystems ON subsystems.sid = groupaccess.sid;

我不确定如何更改视图以使我的查询更有效,因为它们现在大约需要 1-4 秒,在某些情况下最多需要 8 秒。

我的另一个想法是使用内存缓存,但这感觉就像解决低效视图问题的创可贴一样。

这是 EXPLAIN ANALYZE 的输出:

                                                        QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=1.18..4.54 rows=1 width=4) (actual time=0.043..0.043 rows=0 loops=1)
   Join Filter: (groups.gid = users.gid)
   ->  Nested Loop  (cost=1.18..3.34 rows=1 width=8) (actual time=0.040..0.040 rows=0 loops=1)
         ->  Hash Join  (cost=1.18..2.78 rows=1 width=4) (actual time=0.039..0.039 rows=0 loops=1)
               Hash Cond: (groupaccess.sid = subsystems.sid)
               ->  Seq Scan on groupaccess  (cost=0.00..1.43 rows=43 width=8) (actual time=0.014..0.014 rows=1 loops=1)
               ->  Hash  (cost=1.17..1.17 rows=1 width=4) (actual time=0.017..0.017 rows=0 loops=1)
                     Buckets: 1024  Batches: 1  Memory Usage: 0kB
                     ->  Seq Scan on subsystems  (cost=0.00..1.17 rows=1 width=4) (actual time=0.015..0.015 rows=0 loops=1)
                           Filter: (((application)::text = 'LoginLink'::text) AND ((subsystem)::text = '1'::text))
         ->  Index Scan using groups_pkey on groups  (cost=0.00..0.55 rows=1 width=4) (never executed)
               Index Cond: (gid = groupaccess.gid)
   ->  Seq Scan on users  (cost=0.00..1.19 rows=1 width=8) (never executed)
         Filter: (uid = 2)
 Total runtime: 0.192 ms
(15 rows)

这完全让我困惑,因为当我用 PHP 将其放入 PDO 时,查询需要几秒钟,而不是几分之一秒。

I have a SELECT statement that makes a very simple query from a more complicated view:

I have a fairly straight-forward select statement:

SELECT uid
FROM   userpermissions
WHERE  uid         = :whoami
AND    application = :application
AND    subsystem   = :subsystem
;

And my view is only ints and varchars, but a join of four tables (likely to be the real problem).

                       View "public.userpermissions"
   Column    |          Type          | Modifiers | Storage  | Description
-------------+------------------------+-----------+----------+-------------
 uid         | integer                |           | plain    |
 gid         | integer                |           | plain    |
 sid         | integer                |           | plain    |
 name        | character varying(128) |           | extended |
 application | character varying(128) |           | extended |
 subsystem   | character varying(128) |           | extended |
View definition:
 SELECT users.uid, groups.gid, groupaccess.sid, groups.name, subsystems.application, subsystems.subsystem
   FROM users
   JOIN groups ON groups.gid = users.gid
   JOIN groupaccess ON groups.gid = groupaccess.gid
   JOIN subsystems ON subsystems.sid = groupaccess.sid;

I'm unsure how to change the view so that my queries are more efficient, as they're taking about 1-4 seconds right now, and in some cases up to 8.

My other thought was to use a memcache, but that feels like a band-aid solution to the problem of an inefficient view.

Here's the output from EXPLAIN ANALYZE:

                                                        QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=1.18..4.54 rows=1 width=4) (actual time=0.043..0.043 rows=0 loops=1)
   Join Filter: (groups.gid = users.gid)
   ->  Nested Loop  (cost=1.18..3.34 rows=1 width=8) (actual time=0.040..0.040 rows=0 loops=1)
         ->  Hash Join  (cost=1.18..2.78 rows=1 width=4) (actual time=0.039..0.039 rows=0 loops=1)
               Hash Cond: (groupaccess.sid = subsystems.sid)
               ->  Seq Scan on groupaccess  (cost=0.00..1.43 rows=43 width=8) (actual time=0.014..0.014 rows=1 loops=1)
               ->  Hash  (cost=1.17..1.17 rows=1 width=4) (actual time=0.017..0.017 rows=0 loops=1)
                     Buckets: 1024  Batches: 1  Memory Usage: 0kB
                     ->  Seq Scan on subsystems  (cost=0.00..1.17 rows=1 width=4) (actual time=0.015..0.015 rows=0 loops=1)
                           Filter: (((application)::text = 'LoginLink'::text) AND ((subsystem)::text = '1'::text))
         ->  Index Scan using groups_pkey on groups  (cost=0.00..0.55 rows=1 width=4) (never executed)
               Index Cond: (gid = groupaccess.gid)
   ->  Seq Scan on users  (cost=0.00..1.19 rows=1 width=8) (never executed)
         Filter: (uid = 2)
 Total runtime: 0.192 ms
(15 rows)

Which totally baffles me, because the moment I put it into PDO with PHP the query takes seconds, not fractions of a second.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

暖风昔人 2025-01-03 10:06:04

视图对性能没有帮助。最好是简化事情、授予特定权利等等。但它对查询性能没有任何好处。

您可以尝试删除中间人(视图)并使用此查询:

SELECT u.uid
FROM   users u
JOIN   groupaccess g USING (gid)
JOIN   subsystems  s USING (sid)
WHERE  u.uid = :whoami
AND    s.application = :application
AND    s.subsystem   = :subsystem;

这也删除了另一个中间人,即表groups,它在您的场景中根本不需要。 (除非用户的连接行可能丢失,这是不可能的。)

为了性能,您必须将其设为 物化视图,这是一个完全不同的野兽。
加上各个基础表(和/或物化视图)上的拟合索引。

A view does not help with performance. It is only good to simplify things, grant specific rights and some such. But it has no benefit for query performance.

You could try to cut out the middle-man (the view) and use this query:

SELECT u.uid
FROM   users u
JOIN   groupaccess g USING (gid)
JOIN   subsystems  s USING (sid)
WHERE  u.uid = :whoami
AND    s.application = :application
AND    s.subsystem   = :subsystem;

This also cuts out another middle-man, the table groups, which is not needed at all in your scenario. (Except if the connecting row for a user could be missing, which should not be possible.)

For performance, you would have to make that a materialized view, which is a different beast altogether.
Plus fitting indexes on individual underlying tables (and/or the materialized view).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文