1

我有 2 张桌子,桌子A和桌子B

A(有数千行)

  • ID
  • uuid
  • 姓名
  • 类型
  • 由...制作
  • org_id

B(最多有一百行)

  • org_id
  • 组织名称

我正在尝试获得最佳连接查询以获取带有WHERE子句的计数。我需要一个表中包含“myorg”的表中不同created_bys的计数。我目前有以下查询(产生预期结果),想知道是否可以进一步优化?Aorg_nameB

select count(distinct a.created_by)
from a left join
     b
     on a.org_id = b.org_id 
where b.org_name like '%myorg%';
4

3 回答 3

1

你不需要left join

select count(distinct a.created_by)
from a join
     b
     on a.org_id = b.org_id
where b.org_name like '%myorg%' 

对于这个查询,你需要一个关于 的索引b.org_id,我假设你有。

于 2020-04-04T13:33:34.803 回答
1

我会用exists这个:

select count(distinct a.created_by)
from a
where exists (select 1 from b where b.org_id = a.org_id and b.org_name like '%myorg%')

上的索引b(org_id)会有所帮助。但在性能方面,关键点是:

  • like在两边使用通配符进行搜索不利于性能(这不能利用索引);搜索完全匹配会好得多,或者至少在字符串的左侧没有通配符。

  • count(distinct ...)比普通的贵count();如果您真的不需要distinct,请不要使用它。

于 2020-04-04T13:35:19.383 回答
1

您的查询看起来已经不错了。使用普通的[INNER] JOINor LEFT [OUTER] JOIN,就像 Gordon 建议的那样。但这不会有太大变化。

你提到那张桌子B只有......

最多一百行

虽然桌子A有...

数千行

如果每行有很多行created_by(我希望如此),那么就有可能进行模拟索引跳过扫描(在即将到来的 Postgres 版本之一中,
模拟它的需要可能会消失。)

基本成分是这个多列索引

CREATE INDEX ON a (org_id, created_by);

它可以替换just 上的简单索引,(org_id)也适用于您的简单查询。看:

您的情况有两个并发症:

  1. DISTINCT
  2. 0-norg_id产生于org_name like '%myorg%'

所以优化更难实现。但仍然可以使用一些花哨的 SQL:

SELECT count(DISTINCT created_by)  -- does not count NULL (as desired)
FROM   b
CROSS  JOIN LATERAL (
   WITH RECURSIVE t AS (
      (  -- parentheses required
      SELECT created_by
      FROM   a
      WHERE  org_id = b.org_id
      ORDER  BY created_by
      LIMIT 1
      )
      UNION ALL
      SELECT (SELECT created_by
              FROM   a
              WHERE  org_id = b.org_id
              AND    created_by > t.created_by
              ORDER  BY created_by
              LIMIT  1)
      FROM   t
      WHERE  t.created_by IS NOT NULL  -- stop recursion
      )
   TABLE t
   ) a
WHERE  b.org_name LIKE '%myorg%';

db<>fiddle here(Postgres 12,但也适用于 Postgres 9.6。)

这是子查询中的递归CTELATERAL,使用相关子查询。

它利用上面的多列索引为每个(org_id, created_by). 如果表已足够真空,则使用仅索引扫描。

复杂 SQL的主要目标是完全避免对大表进行顺序扫描(甚至位图索引扫描),并且只读取很少的快速索引元组。

由于增加的开销,对于不利的数据分布(每行很多 org_id和/或只有created_by)可能会慢一些,但在有利的条件下它要快得多,并且可以很好地扩展,即使对于数百万行也是如此您必须进行测试才能找到最佳位置。

有关的:

于 2020-04-04T17:25:39.690 回答