Postgres中半随机行选择的优化

时间:2016-08-05 12:38:34

标签: sql postgresql random

我目前有一个从作业表中随机选择作业的查询:

select jobs.job_id
from jobs
where (jobs.type is null)
  and (jobs.project_id = 5)
  and (jobs.status = 'Available')
offset floor(random() * (select count(*) from jobs
                         where (jobs.type is null) and (jobs.project_id = 5)
                           and (jobs.status = 'Available')))
limit 1

这具有所需的功能,但速度太慢。我正在使用Postgres 9.2,所以我不能使用TABLESAMPLE

从好的方面来说,我不需要它是真正随机的,所以我认为我可以通过使它稍微随机来优化它。

有什么想法吗?

3 个答案:

答案 0 :(得分:1)

我可以建议jobs(project_id, status, type)的索引吗?如果查询尚未在表中定义,那么这可能会加快您的查询速度。

答案 1 :(得分:0)

不使用OFFSETLIMIT,为什么不使用

ORDER BY random() LIMIT 1

如果这也太慢,你可以替换你的子查询

select count(*) from jobs
   where (jobs.type is null) and (jobs.project_id = 5)
      and (jobs.status = 'Available')

类似

SELECT reltuples * <factor> FROM pg_class WHERE oid = <tableoid>

其中<tableoid>jobs表的OID,而<factor>是一个稍微大于子查询WHERE条件选择性的数字。

这样可以节省一次顺序扫描,但有时你不会得到任何结果并且不得不重复查询。

这够好吗?

答案 2 :(得分:0)

一个脏技巧:将随机值存储在表中并在其上构建(部分)索引。 (您可能希望不时地重新随机化该字段,以避免记录永远不被选中; - )

-- assumed table definition
CREATE table jobs
        ( job_id SERIAL NOT NULL PRIMARY KEY
        , type VARCHAR
        , project_id INTEGER NOT NULL
        , status VARCHAR NOT NULL
        -- pre-computed magic random number
        -- , magic DOUBLE PRECISION NOT NULL DEFAULT random()
        );

-- some data to play with
INSERT INTO jobs(type,project_id,status)
SELECT 'aaa' , gs %10 , 'Omg!'
FROM generate_series(1,10000) gs;
UPDATE jobs SET type = NULL WHERE random() < 0.2;
UPDATE jobs SET status = 'Available'  WHERE random() < 0.2;

-- add a column containing random numbers
ALTER TABLE jobs
    ADD column magic DOUBLE PRECISION NOT NULL DEFAULT random()
    ;

CREATE INDEX ON jobs(magic)
    -- index is only applied for the conditions you will be searching
    WHERE status = 'Available' AND project_id = 5 AND type IS NULL
    ;

-- make sure statistics are present
VACUUM ANALYZE jobs;

-- EXPLAIN
SELECT j.job_id
FROM jobs j
WHERE j.type is null
  AND j.project_id = 5
  AND j.status = 'Available'
ORDER BY j.magic
LIMIT 1
        ;

类似的东西可以通过使用具有相当高的增量值(3G附近的一些素数)而不是随机+浮点数的串行来实现。