【问题标题】:SQL Performance, What executes faster in the SELECT and WHERE conditionsSQL 性能,在 SELECT 和 WHERE 条件下执行得更快
【发布时间】:2011-09-14 13:07:13
【问题描述】:

更新:废话!它不是一个整数,而是字符变化(10)

像这样执行查询会使用索引

SELECT t."FieldID"
FROM table t
WHERE t."FieldID" = '0123456789'

但如果我执行此操作则不使用索引

SELECT t."FieldID"
FROM table t
WHERE t."FieldID" LIKE '01%'

或者这个

SELECT t."FieldID"
FROM table t
WHERE "substring"(t."FieldID", 0, 3) = '01'

还有这个

SELECT t."FieldID"
FROM table t
WHERE t."FieldID" ~ '^01'

我的索引是这样的

CREATE UNIQUE INDEX fieldid_index
  ON "table"
  USING btree
  ("FieldID");

运行 PostgreSQL 7.4(是的升级)

我正在优化我的查询,并想知道在语句中的 SELECT 或 WHERE 子句中使用三种类型的表达式之一是否有任何性能提升。

注意:使用这些约束样式执行的查询返回大约 200,000 条记录

示例数据是一个字符变化(10)0123456789,它也被索引

1. (子字符串)

SELECT CASE
    WHEN "substring"(t."FieldID"::text, 0, 3) = '01'::text         
    THEN 'Found Match'::text
    ELSE NULL::text
END AS matching_group

2。 (喜欢)

SELECT CASE
    WHEN t."FieldID"::text LIKE '01%'         
    THEN 'Found Match'::text
    ELSE NULL::text
END AS matching_group

3. (正则表达式)

SELECT CASE
    WHEN t."FieldID" ~ '^01'         
    THEN 'Found Match'::text
    ELSE NULL::text
END AS matching_group

在 WHERE 子句中使用一个比另一个有任何性能优势吗?

1. (子字符串)

WHERE CASE
    WHEN "substring"(t."FieldID"::text, 0, 3) = '01'::text         
    THEN 1
    ELSE 0
END = 1

2。 (喜欢)

WHERE CASE
    WHEN t."FieldID"::text LIKE '01%'         
    THEN 1
    ELSE 0
END = 1

3. (正则表达式)

WHERE CASE
    WHEN t."FieldID" ~ '^01'         
    THEN 1
    ELSE 0
END = 1

在 SELECT 中使用一个选项并在 WHERE 子句中使用不同选项会提高性能吗?

【问题讨论】:

  • 你不能看看执行计划,看看哪个(如果有的话)给你寻找而不是扫描吗?
  • 在单个查询中使用任何选项只给我扫描,我如何调用搜索?结果集约为 200K
  • 0123456789 不是整数,因为整数没有前导零(123456789 是整数值)
  • @Martin Smith:正则表达式 '^01' 看起来确实像一个字符串。整数没有前导零。
  • 这将使范围查询(Martin Smith,上图)再次成为可能。

标签: sql postgresql query-optimization query-performance


【解决方案1】:

我个人认为不应允许制造此类问题的人使用“性能”一词。对数字字段(甚至可能是键字段)内容的文本表示的限制(如 WHERE 子句中的限制)表明设计不佳,恕我直言。

如果这是我的数据,我会在记录中添加一个标志字段,在查询 xyz 中指示想要/不想要。甚至可以将其放入单独的表中。我更喜欢添加一个(冗余?)列来创建基于 GW-basic-substring 垃圾的整个索引。

【讨论】:

  • 感谢您的帮助,我还更新了我的问题,以进一步澄清问题
  • 原来的查询更难看。本主题与性能无关;是关于(缺乏)设计。 stackoverflow.com/questions/7408499/…
  • 可以理解,不是我的设计只是想让项目按照他们的规定工作
【解决方案2】:

影响最大的两件事是索引和可搜索性。 Sargability 意味着使用可以利用索引的表达式。您可以使用

来衡量它们的效果
ANALYZE your_first_table;
-- ANALYZE other tables used in this query.
EXPLAIN ANALYZE
SELECT ...

请参阅Examining index usage 的文档。

您也许可以利用indexes on expressionspartial indexes。 PostgreSQL 7.4 支持表达式索引和部分索引。如需测试,您可以discourage certain kinds of query plans。 (也在 7.4 中。)

可能适合您的基于表达式的索引:

create index firsttwochars
on your-table-name (substring(your-column-name from 1 for 2));

但是您仍然需要测试您的查询以查看它们是否真正使用了索引。 (无论他们是 sargable。)这个可能有用。

select your-column-name 
from your-table-name 
where substring(your-column-name from 1 for 2) = '01'

前两个字符没有索引的查询计划。 (我的测试表使用随机纯文本用户名,这就是我搜索“ab”而不是“01”的原因。)

Seq Scan on substring  (cost=0.00..205.00 rows=50 width=11) (actual time=0.315..4.377 rows=14 loops=1)
  Filter: (substring((username)::text, 1, 2) = 'ab'::text)
Total runtime: 4.414 ms

查询计划前两个字符的索引。

Bitmap Heap Scan on substring  (cost=4.36..37.61 rows=14 width=11) (actual time=0.036..0.056 rows=14 loops=1)
  Recheck Cond: (substring((username)::text, 1, 2) = 'ab'::text)
  ->  Bitmap Index Scan on firsttwochars  (cost=0.00..4.36 rows=14 width=0) (actual time=0.028..0.028 rows=14 loops=1)
        Index Cond: (substring((username)::text, 1, 2) = 'ab'::text)
Total runtime: 0.098 ms

【讨论】:

  • 感谢您的帮助,我还更新了我的问题,以进一步澄清问题
  • @Phill Pafford:PostgreSQL 7.4 支持部分索引和基于表达式的索引,因此您应该能够立即提高性能。 (我以为 8.something 中添加了基于表达式的索引;我错了。)
【解决方案3】:

在 SQL Server 中,带有 LIKE '01%' 的版本将是 sargable。它实际上将这些没有前导通配符的LIKE 查询转换为范围查询。

执行计划将搜索谓词显示为YourCol >= '01' AND YourCol < '02',也许类似的重写可以在 Postgresql 中有所帮助?

【讨论】:

    【解决方案4】:

    在选择列表中,这三个表达式可能不会有太大的区别。这都是 CPU 时间。

    对于WHERE 子句,您可以添加表达式索引,例如

    CREATE INDEX foo ON sometable ((
    CASE
        WHEN "substring"("FieldID"::text, 0, 3) = '01'::text         
        THEN 1
        ELSE 0
    END
    ));
    

    但是这种布尔索引的选择性可能会很糟糕,以至于规划者不会感兴趣。最好将WHERE 子句改写为

    WHERE "substring"("FieldID"::text, 0, 3) = '01'::text
    

    然后索引它。

    对于LIKE 和正则表达式,您也可以考虑使用text_pattern_ops 索引;见documentation

    总而言之,我认为您需要对该查询进行一些清理工作。

    【讨论】:

    • 感谢您的帮助,我还更新了我的问题,以进一步澄清问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-17
    • 2012-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-29
    • 1970-01-01
    相关资源
    最近更新 更多