我有一个Postgre数据库和一个名为my_table的表。该表格中有4列(id
,column1
,column2
,column3
)。 id
列是主键,列上没有其他约束或索引。
该表有大约200000行。
我想将列column2
的值等于(不区分大小写)的所有行打印到'value12'
。我用这个:
SELECT * FROM my_table WHERE column2 = lower('value12')
这是此声明的执行计划(set enable_seqscan=on; EXPLAIN SELECT * FROM my_table WHERE column2 = lower('value12')
的结果):
Seq Scan on my_table (cost=0.00..4676.00 rows=10000 width=55)
Filter: ((column2)::text = 'value12'::text)
我认为这会变慢,所以我在列column2
上创建了一个索引,以便更好地预先搜索:
CREATE INDEX my_index ON my_table (lower(column2))
现在我运行了相同的选择:
SELECT * FROM my_table WHERE column2 = lower('value12')
我希望它更快,因为它可以使用索引。然而它并不快,它和以前一样慢。所以我检查了执行计划,它和以前一样(见上文)。所以它仍然使用顺序情景,它忽略了索引!问题在哪里?
答案 0 :(得分:4)
此:
SELECT *
FROM my_table
WHERE column2 = lower('value12')
...假设column2
中的所有数据都是小写的。如果不是这样的情况将不匹配。
SELECT *
FROM my_table
WHERE LOWER(column2) = LOWER('value12')
在列上使用函数可能会使索引无效。
决策由优化器决定,优化器除了考虑索引之外还要尽可能快地返回结果。据我所知,Postgres没有像MySQL,Oracle或SQL Server中那样提供强制索引使用的语法。
您可以使用SET STATISTICS:
ALTER TABLE <table> ALTER COLUMN <column> SET STATISTICS <number>;
此值可以是介于0和1000之间的数字,并帮助PostgreSQL确定应对该列执行的统计信息收集级别。这有助于您控制生成的查询计划,而不会产生缓慢的真空并分析操作,因为会为所有表和列生成大量统计信息。
答案 1 :(得分:2)
您实际上并未比较column2
的小写值。您正在将column2
的(文字)值与较低版本的'value12'进行比较。
您的意思是与lower(column2)
进行比较吗?
SELECT * FROM my_table WHERE lower(column2) = lower('value12')
答案 2 :(得分:1)
您可能需要使用:
WHERE lower(column2) = lower('value12')
通常,涉及列的表达式必须与索引表达式匹配,以便它能够对该索引进行优化。
答案 3 :(得分:0)
除了关于lower()
的答案之外,这应该说服PostgreSQL使用索引 - 运行explain
来验证。
set enable_seqscan = false;
您可能还想在创建索引后运行vacuum analyze
。