SQL 性能,在 SELECT 和 WHERE 条件中什么执行速度更快
更新:糟糕!它不是一个整数,它是字符变化(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。 (RegEx)
WHERE CASE
WHEN t."FieldID" ~ '^01'
THEN 1
ELSE 0
END = 1
在 SELECT 中使用一个选项并在 WHERE 子句中使用不同的选项会提高性能吗?
UPDATE: Crap! it's not an integer it's character varying(10)
Executing the query like this uses the index
SELECT t."FieldID"
FROM table t
WHERE t."FieldID" = '0123456789'
But does not use the index if I execute this
SELECT t."FieldID"
FROM table t
WHERE t."FieldID" LIKE '01%'
or this
SELECT t."FieldID"
FROM table t
WHERE "substring"(t."FieldID", 0, 3) = '01'
also this
SELECT t."FieldID"
FROM table t
WHERE t."FieldID" ~ '^01'
My index looks like this
CREATE UNIQUE INDEX fieldid_index
ON "table"
USING btree
("FieldID");
Running PostgreSQL 7.4 (Yep Upgrading)
I'm optimizing my query and wanted to know if there is any performance gains using one of the three types of expressions in either the SELECT or WHERE clause in the statement.
NOTE: The query that executes with these style of constraints returns around 200,000 records
Example Data is a character varying(10): 0123456789
and it is indexed as well
1. (Substring)
SELECT CASE
WHEN "substring"(t."FieldID"::text, 0, 3) = '01'::text
THEN 'Found Match'::text
ELSE NULL::text
END AS matching_group
2. (Like)
SELECT CASE
WHEN t."FieldID"::text LIKE '01%'
THEN 'Found Match'::text
ELSE NULL::text
END AS matching_group
3. (RegEx)
SELECT CASE
WHEN t."FieldID" ~ '^01'
THEN 'Found Match'::text
ELSE NULL::text
END AS matching_group
Also is there any performance advantages using one over the other in the WHERE clause?
1. (Substring)
WHERE CASE
WHEN "substring"(t."FieldID"::text, 0, 3) = '01'::text
THEN 1
ELSE 0
END = 1
2. (Like)
WHERE CASE
WHEN t."FieldID"::text LIKE '01%'
THEN 1
ELSE 0
END = 1
3. (RegEx)
WHERE CASE
WHEN t."FieldID" ~ '^01'
THEN 1
ELSE 0
END = 1
Would using one option in the SELECT and a different option in the WHERE clause improve performance?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我个人认为,制造这种问题的人不应该被允许使用“表现”这个词。恕我直言,对数字字段(甚至可能是键字段)内容的文本表示的限制(如 WHERE 子句中的限制)表明设计不好。
如果这是我的数据,我会向记录添加一个标志字段,指示查询 xyz 中想要/不想要。人们甚至可以将其放入一张单独的表中。我更喜欢添加一个(冗余?)列来创建基于 GW-basic-substring 垃圾的整个索引。
Personally I think that someone who creates this kind of a problem should not be allowed to use the word "performance". Restrictions (like those in the WHERE clause) on the text representation of the contents of a numeric field (maybe even a keyfield) indicate bad design, IMHO.
If this were my data, I would add a flagfield to the record, indicating wanted / not wanted in query xyz. One could even put it into a separate table. I prefer adding a (redundant?) column to creating an entire index based on GW-basic-substring rubbish.
最有效的两件事是索引和控制能力。 可控制性意味着使用可以利用索引的表达式。您可以通过使用
查看文档检查索引使用情况 来衡量它们的效果。
您也许可以利用表达式索引或< a href="http://www.postgresql.org/docs/9.1/static/indexes-partial.html" rel="nofollow">部分索引。 PostgreSQL 7.4 支持表达式索引和部分索引。为了进行测试,您可以阻止某些各种查询计划。 (也在 7.4 中。)
基于表达式的索引可能适合您:
但是您仍然需要测试您的查询以查看它们是否实际使用索引。 (无论它们可控制。)这个可能会起作用。
前两个字符上没有索引的查询计划。 (我的测试表使用随机纯文本用户名,这就是我搜索“ab”而不是“01”的原因。)
查询计划前两个字符的索引。
The two things that have the most effect are indexing and sargability. Sargability means using an expression that can take advantage of an index. You measure their effect by using
See the docs for Examining index usage.
You might be able to take advantage of indexes on expressions or partial indexes. PostgreSQL 7.4 supports both indexes on expressions and partial indexes. For testing, you can discourage certain kinds of query plans. (Also in 7.4.)
An expression-based index that might work for you:
But you still need to test your queries to see whether they actually use the index. (Whether they're sargable.) This one might work.
Query plan without the index on the first two characters. (My test table uses random text-only usernames, which is why I searched on 'ab' instead of '01'.)
Query plan with the index on the first two characters.
在 SQL Server 中,带有
LIKE '01%'
的版本将是可控制的。它实际上将这些不带通配符的LIKE
查询转换为范围查询。执行计划将查找谓词显示为
YourCol >= '01' AND YourCol < '02'
也许类似的重写可以在 Postgresql 中有所帮助?In SQL Server the version with
LIKE '01%'
would be sargable. It actually converts theseLIKE
queries without leading wildcards to range queries.The execution plan shows the seek predicate as being
YourCol >= '01' AND YourCol < '02'
perhaps a similar sort of rewrite could help in Postgresql?在选择列表中,这三个表达式之间可能不会有太大区别。都是CPU时间。
对于
WHERE
子句,您可以添加一个表达式索引,例如,但这种布尔索引的选择性可能很糟糕,不会引起规划者的兴趣。最好将
WHERE
子句重写为仅然后对其进行索引。
对于
LIKE
和正则表达式情况,您也可以考虑使用text_pattern_ops
索引;请参阅文档。总而言之,我认为您需要对该查询进行一些清理工作。
In the select list, there will probably not be much difference between the three expressions. It's all CPU time.
For the
WHERE
clause, you could add an expression index such asbut the selectivity of such a Boolean index will likely be bad enough to not interest the planner. It would be better to rewrite the
WHERE
clause to justand then index that.
For the
LIKE
and regex cases you could consider atext_pattern_ops
index as well; see the documentation.All in all, I think you have some cleanup work to do on that query.