with r as (
select distinct
ceil(
random() *
(select max(image_id) from image)
)::int as image_id
from generate_series(1, 200)
limit 100
)
select image_id
from image inner join r using (image_id)
limit 50
由于主键存在间隙,必须将表连接到50个以上的随机生成ID上,以确保至少有50个。需要多少个取决于PK的“不连续性”。在样本表中,每5个缺失2个。
为了拥有不同的随机生成ID,还需要生成超过(在上述示例中)100个进行连接。需要多少个取决于表的大小。对于非常大的表,只需要更少的数量。
即使上述数字夸张了,对性能的影响也可以忽略不计。为了使其不返回已经看到的图像,我会创建一个带有session_id
(或user_id
,以获得更长的过期时间)和image_id
的seem_images
表,并在每个GetImages
中插入其中。无需额外的函数GetMoreImages
。
with r as (
select distinct
ceil(
random() *
(select max(image_id) from image)
)::int as image_id
from generate_series(1, 200)
limit 100
), t as (
select image_id, image
from image inner join r using (image_id)
where not exists (
select 1
from seem_image
where image_id = image.image_id and session_id = 1
)
limit 50
), i as (
insert into seem_image (image_id, session_id)
select image_id, 1
from t
)
select * from t;
上面的查询将只返回非看起来的图像。在样本3百万行image
表中,它非常快。对于长时间的图像浏览和会话,需要从100
和200
以上更改为适当的数字。过期的会话应该根据会话到期时间定期从seem_image
表中删除,以避免它变得太大。
样例image
(带有间隙的整数作为主键)和seem_image
表格
create table image (
image_id integer primary key,
image bytea
);
insert into image (image_id, image)
select image_id, image
from
generate_series(1, 5000000) g (image_id)
cross join
(values (decode(rpad('', 1024 * 100, 'F'), 'hex'))) i (image)
where mod (image_id, 5) not in (0, 1)
;
analyze image;
create table seem_image (
session_id integer,
image_id integer,
primary key (image_id, session_id)
);
ORDER BY random()
都会这样做。所以不用在意。 - Craig Ringer