Sql 延迟排序依据/何处求值

Sql 延迟排序依据/何处求值,sql,database,postgresql,database-design,Sql,Database,Postgresql,Database Design,编辑 似乎一个纯粹的物化可以存储为表上的一列并索引;但是,我的特定用例semver.empts需要一个更通用的解决方案: create table Submissions ( version text created_at timestamp ) create index Submissions_1 on Submissions (created_at) 我的查询将如下所示: select * from Submissions where created_at <

编辑

似乎一个纯粹的物化可以存储为表上的一列并索引;但是,我的特定用例semver.empts需要一个更通用的解决方案:

create table Submissions (
    version text
    created_at timestamp
)

create index Submissions_1 on Submissions (created_at)
我的查询将如下所示:

select * from Submissions
where
    created_at <= '2016-07-12' and
    satisfies(version, '>=1.2.3 <4.5.6')
order by created_at desc
limit 1;
给定校验和参考日期,我希望获得内容字段与该校验和匹配的最新提交:

select * from Submissions
where
    created_at <= '2016-07-12' and
    expensive_chksm(content) = '77ac76dc0d4622ba9aa795acafc05f1e'
order by created_at desc
limit 1;
没有orderby,这是一个亚毫秒级的操作,因为Postgres知道我只想要第一个结果。唯一的区别是我希望Postgres从最晚的日期开始搜索

理想情况下,博士后应该:

按以下位置创建的过滤器 按处创建的排序,降序 返回校验和匹配的第一行
我曾尝试使用内联视图编写查询,但解释分析表明,它将被重写为我上面已有的内容。

如果您总是要查询校验和,则另一种选择是在表中有另一个名为校验和的列,例如:

create table Submissions (
    content text,
    created_at timestamp,
    checksum varchar
);
然后,无论何时插入/更新行,您都可以插入/更新校验和,或者编写一个触发器来为您执行此操作,并直接查询校验和列以获得快速结果。

尝试此方法

select *
from Submissions
where created_at = (
  select max(created_at) 
  from Submissions 
  where expensive_chksm(content) = '77ac76dc0d4622ba9aa795acafc05f1e')

您可以对时间戳和订购部件使用子查询,然后在外部运行chksum:

select * from (
  select * from submissions where
    created_at <= '2016-07-12' and
    order by created_at desc) as S 
where expensive_chksm(content) = '77ac76dc0d4622ba9aa795acafc05f1e'
LIMIT 1

您可以同时为这两个字段创建索引:

create index Submissions_1 on Submissions (created_at DESC, expensive_chksm(content));

                                                                        QUERY PLAN                                                                         
-----------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.15..8.16 rows=1 width=40) (actual time=0.004..0.004 rows=0 loops=1)
   ->  Index Scan using submissions_1 on submissions  (cost=0.15..16.17 rows=2 width=40) (actual time=0.002..0.002 rows=0 loops=1)
         Index Cond: ((created_at <= '2016-07-12 00:00:00'::timestamp without time zone) AND ((content)::text = '77ac76dc0d4622ba9aa795acafc05f1e'::text))
 Planning time: 0.414 ms
 Execution time: 0.036 ms
在索引中使用DESC也很重要

更新: 对于存储和比较版本,可以使用int[]

create table Submissions (
    version int[],
    created_at timestamp
);

INSERT INTO Submissions SELECT ARRAY [ (random() * 10)::int2, (random() * 10)::int2, (random() * 10)::int2], '2016-01-01'::timestamp + ('1 hour')::interval * random() * 10000 FROM generate_series(1, 1000000);

    create index Submissions_1 on Submissions (created_at DESC, version);

EXPLAIN ANALYZE select * from Submissions
where
    created_at <= '2016-07-12'
    AND version <= ARRAY [5,2,3]
    AND version > ARRAY [1,2,3]
order by created_at desc
limit 1;

                                                                             QUERY PLAN                                                                              
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.42..13.24 rows=1 width=40) (actual time=0.074..0.075 rows=1 loops=1)
   ->  Index Only Scan using submissions_1 on submissions  (cost=0.42..21355.76 rows=1667 width=40) (actual time=0.073..0.073 rows=1 loops=1)
         Index Cond: ((created_at <= '2016-07-12 00:00:00'::timestamp without time zone) AND (version <= '{5,2,3}'::integer[]) AND (version > '{1,2,3}'::integer[]))
         Heap Fetches: 1
 Planning time: 3.019 ms
 Execution time: 0.100 ms
对一匹没有名字评论的马:
where子句中条件的顺序与索引的使用无关。最好先将可用于等式表达式的表达式放在索引中,然后再放在范围表达式中

BEGIN;

create table Submissions (
    content text,
    created_at timestamp
);


CREATE FUNCTION  expensive_chksm(varchar) RETURNS varchar AS $$
SELECT $1;
$$ LANGUAGE sql;

INSERT INTO Submissions SELECT (random() * 1000000000)::text, '2016-01-01'::timestamp + ('1 hour')::interval * random() * 10000 FROM generate_series(1, 1000000);
INSERT INTO Submissions SELECT '77ac76dc0d4622ba9aa795acafc05f1e', '2016-01-01'::timestamp + ('1 hour')::interval * random() * 10000 FROM generate_series(1, 100000);

    create index Submissions_1 on Submissions (created_at DESC, expensive_chksm(content));
--    create index Submissions_2 on Submissions (expensive_chksm(content), created_at DESC);

EXPLAIN ANALYZE select * from Submissions
where
    created_at <= '2016-07-12' and
    expensive_chksm(content) = '77ac76dc0d4622ba9aa795acafc05f1e'
order by created_at desc
limit 1;
使用Submission1:

                                                                        QUERY PLAN                                                                         
-----------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.43..10.98 rows=1 width=40) (actual time=0.018..0.019 rows=1 loops=1)
   ->  Index Scan using submissions_1 on submissions  (cost=0.43..19341.43 rows=1833 width=40) (actual time=0.018..0.018 rows=1 loops=1)
         Index Cond: ((created_at <= '2016-07-12 00:00:00'::timestamp without time zone) AND ((content)::text = '77ac76dc0d4622ba9aa795acafc05f1e'::text))
 Planning time: 0.257 ms
 Execution time: 0.033 ms
使用Submission2:

                                                                             QUERY PLAN                                                                               
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=4482.39..4482.40 rows=1 width=40) (actual time=29.096..29.096 rows=1 loops=1)
   ->  Sort  (cost=4482.39..4486.98 rows=1833 width=40) (actual time=29.095..29.095 rows=1 loops=1)
         Sort Key: created_at DESC
         Sort Method: top-N heapsort  Memory: 25kB
         ->  Bitmap Heap Scan on submissions  (cost=67.22..4473.23 rows=1833 width=40) (actual time=15.457..23.683 rows=46419 loops=1)
               Recheck Cond: (((content)::text = '77ac76dc0d4622ba9aa795acafc05f1e'::text) AND (created_at <= '2016-07-12 00:00:00'::timestamp without time zone))
               Heap Blocks: exact=936
               ->  Bitmap Index Scan on submissions_1  (cost=0.00..66.76 rows=1833 width=0) (actual time=15.284..15.284 rows=46419 loops=1)
                     Index Cond: (((content)::text = '77ac76dc0d4622ba9aa795acafc05f1e'::text) AND (created_at <= '2016-07-12 00:00:00'::timestamp without time zone))
 Planning time: 0.583 ms
 Execution time: 29.134 ms

PostgreSQL 9.6.1

谢谢您的回答!您的解决方案确实适用于验证校验和之类的简单事情。在我的项目中,我使用一个semver.summits扩展来检查给定范围的版本字段,所以很遗憾,我不能使用相同的解决方案。如果你有更好的类比,我很乐意更新这个问题!版本字段也是提交表的一部分吗?我的实际表如下所示:版本文本,在时间戳处创建,我的where子句如下所示:在它处创建,仍然需要计算所有行上的chksm,以便找到答案的最大创建数!不幸的是,查询规划师只是把它改写成了我以前拥有的东西。而且,如果有办法防止它被改写,我会得到我所需要的!实际上,最好按相反的顺序进行索引:创建索引提交\u chksum\u创建\u desc\u idx关于提交的内容\u chksmcontent,在desc创建;因为数据库总是能够使用二进制搜索来查找行。不,索引的顺序必须与查询中的顺序相同。另一种方式是使用-索引扫描位图索引扫描+位图堆扫描+排序where子句中条件的顺序与索引的使用无关。最好先将可用于等式表达式的表达式放在索引中,然后再放在范围表达式中。@RomanTkachuk,是的,他需要按desc创建的昂贵的chksmcontent排序,这不会改变顺序,但会让Postgres相信它可以使用索引。即使创建了许多行,我的想法仍然有效。atI无法使用简单的数组比较。Semver有一些奇怪的规则,很难用普通SQL实现。最好假设满足函数是唯一的真值来源。如果存储得更合理一些,可以使用正常比较和正常索引,例如bigint 100000200003而不是1.2.3,4000005000006而不是4.5.6 major*10^12+minor*10^6+release。这是个好主意,但semver确实很棘手。我已经尝试过几种方法,似乎我目前正在尝试的方法会产生最佳的性能-准确性平衡。我已经更新了问题以澄清。可能比使用int[]->[1,2,3]更好吗?这也是一个很好的指标,比较好吗?
                                                                        QUERY PLAN                                                                         
-----------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.43..10.98 rows=1 width=40) (actual time=0.018..0.019 rows=1 loops=1)
   ->  Index Scan using submissions_1 on submissions  (cost=0.43..19341.43 rows=1833 width=40) (actual time=0.018..0.018 rows=1 loops=1)
         Index Cond: ((created_at <= '2016-07-12 00:00:00'::timestamp without time zone) AND ((content)::text = '77ac76dc0d4622ba9aa795acafc05f1e'::text))
 Planning time: 0.257 ms
 Execution time: 0.033 ms
                                                                             QUERY PLAN                                                                               
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=4482.39..4482.40 rows=1 width=40) (actual time=29.096..29.096 rows=1 loops=1)
   ->  Sort  (cost=4482.39..4486.98 rows=1833 width=40) (actual time=29.095..29.095 rows=1 loops=1)
         Sort Key: created_at DESC
         Sort Method: top-N heapsort  Memory: 25kB
         ->  Bitmap Heap Scan on submissions  (cost=67.22..4473.23 rows=1833 width=40) (actual time=15.457..23.683 rows=46419 loops=1)
               Recheck Cond: (((content)::text = '77ac76dc0d4622ba9aa795acafc05f1e'::text) AND (created_at <= '2016-07-12 00:00:00'::timestamp without time zone))
               Heap Blocks: exact=936
               ->  Bitmap Index Scan on submissions_1  (cost=0.00..66.76 rows=1833 width=0) (actual time=15.284..15.284 rows=46419 loops=1)
                     Index Cond: (((content)::text = '77ac76dc0d4622ba9aa795acafc05f1e'::text) AND (created_at <= '2016-07-12 00:00:00'::timestamp without time zone))
 Planning time: 0.583 ms
 Execution time: 29.134 ms