我有一张简单的桌子。
CREATE TABLE posts
(
id uuid NOT NULL,
vote_up_count integer,
vote_down_count integer,
CONSTRAINT post_pkey PRIMARY KEY(id)
);
我有一个IMMUTABLE
函数可以执行简单(但可能很复杂)算术。
CREATE OR REPLACE FUNCTION score(
ups integer,
downs integer)
RETURNS integer AS
$BODY$
select $1 - $2
$BODY$
LANGUAGE sql IMMUTABLE
COST 100;
ALTER FUNCTION score(integer, integer)
OWNER TO postgres;
我在posts
表上创建了一个使用我的函数的索引。
CREATE INDEX posts_score_index ON posts(score(vote_up_count, vote_down_count), date_created);
当我EXPLAIN
以下查询时,它似乎没有使用索引。
SELECT * FROM posts ORDER BY score(vote_up_count, vote_down_count), date_created
Sort (cost=1.02..1.03 rows=1 width=310)
Output: id, date_created, last_edit_date, slug, sub_id, user_id, user_ip, type, title, content, url, domain, send_replies, vote_up_count, vote_down_count, verdict, approved_by, removed_by, verdict_message, number_of_reports, ignore_reports, number_of_com (...)"
Sort Key: ((posts.vote_up_count - posts.vote_down_count)), posts.date_created
-> Seq Scan on public.posts (cost=0.00..1.01 rows=1 width=310)
Output: id, date_created, last_edit_date, slug, sub_id, user_id, user_ip, type, title, content, url, domain, send_replies, vote_up_count, vote_down_count, verdict, approved_by, removed_by, verdict_message, number_of_reports, ignore_reports, number_ (...)
如何让我的ORDER BY使用IMMUTABLE
函数中可能有一些非常复杂算术的索引?
编辑:基于@Егор-Рогов的建议,我稍微更改了一下查询,看看我是否可以使用索引。仍然没有运气。
set enable_seqscan=off;
EXPLAIN VERBOSE select date_created from posts ORDER BY (hot(vote_up_count, vote_down_count, date_created),date_created);
这是输出。
Sort (cost=10000000001.06..10000000001.06 rows=1 width=16)
Output: date_created, (ROW(round((((log((GREATEST(abs((vote_up_count - vote_down_count)), 1))::double precision) * sign(((vote_up_count - vote_down_count))::double precision)) + ((date_part('epoch'::text, date_created) - 1134028003::double precision) / 4 (...)
Sort Key: (ROW(round((((log((GREATEST(abs((posts.vote_up_count - posts.vote_down_count)), 1))::double precision) * sign(((posts.vote_up_count - posts.vote_down_count))::double precision)) + ((date_part('epoch'::text, posts.date_created) - 1134028003::dou (...)
-> Seq Scan on public.posts (cost=10000000000.00..10000000001.05 rows=1 width=16)
Output: date_created, ROW(round((((log((GREATEST(abs((vote_up_count - vote_down_count)), 1))::double precision) * sign(((vote_up_count - vote_down_count))::double precision)) + ((date_part('epoch'::text, date_created) - 1134028003::double precision (...)
EDIT2 :由于date_created
的第二个订单,我似乎没有使用索引。
答案 0 :(得分:1)
我可以看到一些不鼓励计划者使用索引的要点。
1。 在解释输出中查看这一行:
Seq Scan on public.posts (cost=0.00..1.01 rows=1 width=310)
它说计划者认为表中只有一行。在这种情况下,使用索引扫描是没有意义的,因为顺序扫描更快。
尝试向表中添加更多行,执行analyze
并重试。您还可以通过set enable_seqscan=off;
暂时禁用顺序扫描来测试它。
2。
您可以使用该函数对结果进行排序。因此规划人员可能决定使用索引以便以正确的顺序获取元组ID。但是它需要从表中获取每个元组以获取所有列的值(因为select *
)。
您可以通过向其添加所有必需的列来使索引对规划器更具吸引力,从而避免表扫描。这称为仅索引扫描。
CREATE INDEX posts_score_index ON posts(
score(vote_up_count, vote_down_count),
date_created,
id, -- do you actually need it in result set?
vote_up_count, -- do you actually need it in result set?
vote_down_count -- do you actually need it in result set?
);
确保在插入/更新/删除行后vacuum
更新visibility map。{/ p>
缺点是指数大小增加了。