2

更新:废话!它不是一个整数它的字符变化(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 子句中使用不同选项会提高性能吗?

4

4 回答 4

3

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

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

于 2011-09-14T14:10:09.053 回答
3

影响最大的两件事是索引和可搜索性。Sargability意味着使用可以利用索引的表达式。您可以通过使用来衡量它们的效果

ANALYZE your_first_table;
-- ANALYZE other tables used in this query.
EXPLAIN ANALYZE
SELECT ...

请参阅检查索引使用的文档。

您也许可以利用表达式部分索引上的索引。PostgreSQL 7.4 支持表达式索引和部分索引。对于测试,您可以阻止某些类型的查询计划。(也在 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
于 2011-09-14T14:15:10.980 回答
1

在选择列表中,这三个表达式之间可能不会有太大的区别。这都是 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

然后索引。

对于 theLIKE和 regex 情况,您也可以考虑使用text_pattern_ops索引;请参阅文档

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

于 2011-09-14T14:21:12.633 回答
1

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

执行计划显示搜索谓词YourCol >= '01' AND YourCol < '02'可能是一种类似的重写可能有助于 Postgresql?

于 2011-09-14T16:24:05.277 回答