[PostgreSQL] RANDOM SELECT์™€ ์„ฑ๋Šฅ

์‹ค์ œ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋‹ค๋ณด๋ฉด, ๋•Œ๋•Œ๋กœ๋Š” ๋žœ๋ค์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๊ณ  ์‹ถ์„ ๋•Œ๊ฐ€ ์žˆ๋‹ค.
๊ทธ๋Ÿด๋•Œ ํ”ํžˆ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ORDER BY ์ ˆ์— ๋žœ๋ค๊ฐ’์„ ๋„˜๊ฒจ์„œ ๋ฌด์ž‘์œ„ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด๋‹ค.

์ด ๋ฐฉ๋ฒ•์€ ๊ตฌํ˜„์ด ๊ฐ„๋‹จํ•˜๊ณ  ์ง๊ด€์ ์ด๋‚˜, ๋ฐ์ดํ„ฐ์˜ ํฌ๊ธฐ๊ฐ€ ์ปค์ง„๋‹ค๋ฉด ์ œ ์„ฑ๋Šฅ์„ ๋‚ด๊ธฐ ์–ด๋ ต๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค. ํ…Œ์ด๋ธ”์„ ์ „์ฒด ํ’€์Šค์บ”์„ ๋Œ๋ฆฐ ๋‹ค์Œ์—, ๋‚œ์ˆ˜๊ฐ’์œผ๋กœ ์ „์ฒด ์ •๋ ฌ์„ ๋Œ๋ฆฌ๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
๋ณธ์งˆ์ ์œผ๋กœ ์ธ๋ฑ์Šค๋ฅผ ํ™œ์šฉํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ตฌ์กฐ๋‹ค.

๊ทธ๋ž˜์„œ ์—ฌ๊ธฐ์„œ๋Š” ๋žœ๋ค์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฝ‘์•„์˜ฌ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•๋“ค ๋ช‡๊ฐ€์ง€๋ฅผ ์†Œ๊ฐœํ•ด๋ณด๊ณ , ๊ฐ ์„ฑ๋Šฅ๊ณผ ํ•œ๊ณ„์ ์„ ์ •๋ฆฌํ•ด๋ณด๋ ค ํ•œ๋‹ค.




๋ฐ์ดํ„ฐ ์„ธํŒ…

์‹ค์ œ ์„ฑ๋Šฅ ๋น„๊ต๋ฅผ ์œ„ํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ ๋‹นํžˆ 2000๋งŒ๊ฐœ ์ •๋„๋งŒ ์„ธํŒ…ํ•ด๋ดค๋‹ค.

CREATE TABLE foo (
    id BIGSERIAL PRIMARY KEY,
    a BIGINT NOT NULL,
    b BIGINT NOT NULL,
    c BIGINT NOT NULL
);

INSERT INTO foo (a, b, c)
SELECT
    (random() * 100)::INTEGER as a,
    (random() * 1000)::INTEGER as b,
    (random() * 10000)::INTEGER as c
FROM
    generate_series(1, 20000000) AS t;




ORDER BY RANDOM

๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ๊ตฌํ˜„๋ฒ•์ด๋‹ค.

explain(analyze) select * from foo order by random() limit 100;

์ด ๋ฐฉ๋ฒ•์€ ์œ„์—์„œ ๋งํ–ˆ๋“ฏ, ํ’€์Šค์บ” ํ›„ ์ •๋ ฌ์„ ํ•˜๋Š” ๊ฒƒ์ด๋ผ ๋Œ€๊ทœ๋ชจ ๋ฐ์ดํ„ฐ์…‹์— ๋Œ€ํ•ด์„œ๋Š” ์„ฑ๋Šฅ์„ ์žฅ๋‹ดํ•  ์ˆ˜ ์—†๋‹ค.
์ด ๊ฒฝ์šฐ์—๋งŒ ํ•ด๋„ 2์ดˆ ์ •๋„๋‚˜ ๊ฑธ๋ ธ๋‹ค.

๋งค์šฐ ๋А๋ฆฌ๊ณ , ๋ฐ์ดํ„ฐ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ๋ถˆ๋ฆฌํ•ด์ง€๋‚˜. ๋žœ๋ค ๋ถ„ํฌ ์ž์ฒด์— ๋Œ€ํ•ด์„œ๋Š” ๊ฐ€์žฅ ์™„๋ฒฝํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค.




OFFSET RANDOM()

ํ–‰์ด ์ด ๋ช‡๊ฐœ์ธ์ง€ ์•Œ๊ณ ์žˆ๋‹ค๋ฉด, ๊ทธ๋ƒฅ OFFSET์— ๋žœ๋ค๊ฐ’์„ ๋„ฃ์–ด์„œ ๋Œ๋ฆฌ๋Š” ๊ฒƒ๋„ ๊ฝค ๋‚˜์˜์ง€ ์•Š์€ ๋ฐฉ๋ฒ•์ด๋‹ค.
์šฐ๋ฆฌ๋Š” 2000๋งŒ๊ฐœ๋ผ๋Š”๊ฑธ ์•Œ๊ณ  ์žˆ์œผ๋ฏ€๋กœ, ๊ทธ๋ƒฅ ์ด๋Ÿฐ ์‹์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ ค๋ณผ ์ˆ˜๋„ ์žˆ๋‹ค.

explain(analyze) SELECT * FROM foo OFFSET floor(random() * 20000000) LIMIT 100;

์‚ฌ์‹ค OFFSET ์ž์ฒด๋„ ํ’€์Šค์บ” ๊ธฐ๋ฐ˜์œผ๋กœ ์ธ๋ฑ์Šค๋ฅผ ์Šคํ‚ตํ•˜๋Š”๊ฑฐ๋ผ, ์ธ๋ฑ์Šค๋ฅผ ํƒ€์ง€ ๋ชปํ•œ๋‹ค๋Š” ๊ฒƒ์€ ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š๋‹ค.
์ตœ์•…์˜ ๊ฒฝ์šฐ, ์˜คํ”„์…‹์ด ๊ฑฐ์˜ ๋งจ ๋’ค์— ์žˆ๋‹ค๋ฉด ์ „์ฒด ๋ฐ์ดํ„ฐ๋ฅผ ํ’€์Šค์บ”ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋‚˜์„ ๊ฒƒ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ทธ๋ž˜๋„ ํ™•๋ฅ ์ ์œผ๋กœ๋Š” ๋งจ ๋’ค๊นŒ์ง€ ๋‚œ์ˆ˜๊ฐ€ ์žกํž ํ™•๋ฅ ์€ ๋‚ฎ๊ณ , ๋ฌด๊ฑฐ์šด ์ •๋ ฌ๋„ ์—†๊ธฐ ๋•Œ๋ฌธ์—, ์•„๊นŒ ์ฒ˜์Œ๋ณด๋‹ค๋Š” ์ฒ˜๋ฆฌ์†๋„๊ฐ€ ๋นจ๋ผ์ง„ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
๋Œ€์ฒด๋กœ๋Š” ์˜คํ”„์…‹์ด ์šด์ข‹๊ฒŒ ์ดˆ๋ฐ˜์— ์žกํžˆ๋ฉด ๋ฐ€๋ฆฌ์ดˆ ๋‹จ์œ„๋กœ๋„ ๋๊ณ , ์›ฌ๋งŒํ•˜๋ฉด 1์ดˆ ์•„๋ž˜๋กœ ์‹คํ–‰์ด ๋๋‹ค.

๋‹จ์ ์€, ๋žœ๋ค ๋ถ„ํฌ๊ฐ€ ๊ณ ๋ฅด์ง€ ์•Š๊ณ  ์ˆœ์ฐจ์ ์œผ๋กœ ๋ญ‰์ณ์ ธ ์žˆ๋Š” ๋ฉ์–ด๋ฆฌ ๋‹จ์œ„๋กœ๋งŒ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค. ๊ณ ๋ฅด๊ฒŒ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด ์—ฌ๋Ÿฌ๋ฒˆ์— ๊ฑธ์ณ ํ•œ๊ฐœ์”ฉ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ํ•ด์•ผํ•œ๋‹ค.




RANDOM() < 0.01

ํ•„ํ„ฐ๋ง ๊ธฐ๋ฐ˜์œผ๋กœ ํ–‰์„ ๊ฑฐ๋ฅด๋Š” ๊ฒƒ๋„ ํ•˜๋‚˜์˜ ๋ฐฉ๋ฒ•์ด๋‹ค.
์•Œ๋‹ค์‹œํ”ผ RANDOM()์€ 1.0-0 ๋ฒ”์œ„์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ณ , 0.01๋ณด๋‹ค ์ž‘์€๊ฒƒ๋งŒ ํ•„ํ„ฐ๋งํ•œ๋‹ค๋ฉด ํ™•๋ฅ ์ ์œผ๋กœ 1%์˜ ํ–‰๋งŒ ํ•„ํ„ฐ๋งํ•˜๋Š” ์…ˆ์ด ๋œ๋‹ค.

์‹ค์ œ๋กœ๋„ 1%์ธ 20๋งŒ๊ฐœ ์ •๋„์˜ ํ–‰๋งŒ ์ง‘๊ณ„๊ฐ€ ๋œ๋‹ค.

์ด๊ฑธ ์‘์šฉํ•˜๋ฉด ๋žœ๋ค์œผ๋กœ ์ผ๋ถ€ ๋ถ€๋ถ„์ง‘ํ•ฉ์„ ๋น ๋ฅด๊ฒŒ ๋นผ๋‚ด๋Š” ๋ฐฉ๋ฒ•์„ ์ทจํ•  ์ˆ˜ ์žˆ๋‹ค. ์ธ์œ„์ ์ธ ์ƒ˜ํ”Œ๋ง์ด๋‹ค.

explain(analyze) select * from foo where random() < 0.01 limit 100;

์ด๋Ÿฌ๋ฉด ์•ž๋ถ€๋ถ„์— ์žˆ๋Š” ํ–‰๋งŒ ๋‚˜์˜ฌ ๊ฐ€๋Šฅ์„ฑ์ด ํฌ๊ณ , ๋’ค์—์žˆ๋Š”๊ฑด ๊ฑฐ์˜ ๋ฒ„๋ ค์งˆ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋žœ๋ค์„ฑ์€ ๋‚ฎ์€ ํŽธ์ด๋‹ค.
ํ•˜์ง€๋งŒ ๋งค์šฐ ๋น ๋ฅด๋‹ค๋Š”๊ฒŒ ์žฅ์ ์ด๋‹ค.




TABLESAMPLE

TABLESAMPLE์€ ํ…Œ์ด๋ธ”์—์„œ ์ผ๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋น ๋ฅด๊ฒŒ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•œ ์šฉ๋„๋กœ ์ œ๊ณต๋˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.
๋‚˜๋ฆ„ SQL ํ‘œ์ค€์•ˆ์— ์ •์˜๋œ ๊ธฐ๋Šฅ์ด๊ณ , ๋”ฑ ์ด๋Ÿฐ ์‚ฌ์šฉ์‚ฌ๋ก€๋ฅผ ์œ„ํ•ด ์ œ๊ณต๋œ๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹ค์Œ ์ฟผ๋ฆฌ๋Š” ํ…Œ์ด๋ธ”์˜ 1%๋ฅผ ์ƒ˜ํ”Œ๋งํ•ด์„œ ๊ฐ€์ ธ์˜จ ๋‹ค์Œ์— ๊ฑฐ๊ธฐ์„œ 100๊ฐœ๋งŒ ๊ฐ€์ ธ์˜จ๋‹ค.

explain(analyze) SELECT * FROM foo TABLESAMPLE SYSTEM(1) LIMIT 100;

๋žœ๋ค ์„ ํƒ ์ž์ฒด๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์ œ๊ณตํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋ผ์„œ, ๋ถˆํ•„์š”ํ•œ ์˜ค๋ฒ„ํ—ค๋“œ ์—†์ด ๋งค์šฐ ๋น ๋ฅด๋‹ค๋Š”๊ฒŒ ์žฅ์ ์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ƒ˜ํ”Œ๋ง ๋ฐฉ์‹๋„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” SYSTEM ๋ฐฉ์‹์„ ์ผ์ง€๋งŒ, ์ด์™ธ์—๋„ BERNOULLI, REPEATABLE๋ผ๋Š” ์˜ต์…˜์ด ์กด์žฌํ•œ๋‹ค.




TABLESAMPLE - System

System์€ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ํ˜•ํƒœ์˜ ์ƒ˜ํ”Œ๋ง ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค.

System์€ ์ € ๋น„์œจ๊ฐ’์„ ๊ธฐ๋ฐ˜์œผ๋กœ "ํŽ˜์ด์ง€"๋ฅผ ๋ฌด์ž‘์œ„๋กœ ์„ ํƒํ•ด์„œ ์Šค์บ”ํ•œ๋‹ค.
ํŽ˜์ด์ง€์— ๋ฐ์ดํ„ฐ๊ฐ€ ๋ช‡๊ฐœ ๋“ค์–ด์žˆ์„์ง€๋Š” ํ™•์‹คํžˆ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์—, ๋™์ผํ•œ ๋น„์œจ๋กœ ์‹คํ–‰ํ•˜๋”๋ผ๋„ ์‹ค์ œ ํ–‰ ๊ฐœ์ˆ˜๋Š” ๊ทธ๋•Œ๊ทธ๋•Œ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค๋Š”๊ฒŒ ๋‹จ์ ์ด๋‹ค.
๊ทธ๋ฆฌ๊ณ  ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ์ฝ์–ด์˜ค๋Š” ๊ฑฐ๋ผ์„œ ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ๊ฐ’์ด ๋ชจ์—ฌ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ๋žœ๋ค ๋ถ„ํฌ ์ˆ˜์ค€์ด ๊ทธ๋ฆฌ ๋†’์ง€ ์•Š๋‹ค.


์„ฑ๋Šฅ ์ž์ฒด๋Š” ๊ฐ€์žฅ ๋น ๋ฅธ ์ถ•์— ์†ํ•œ๋‹ค.




TABLESAMPLE - BERNOULLI

BERNOULLI๋Š” ์กฐ๊ธˆ ๋” ์ง„์งœ ๋žœ๋ค ์„ ํƒ์— ๊ฐ€๊นŒ์šด ๋ฐฉ์‹์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.
์ด๊ฑด ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ ์ฝ์ง€ ์•Š๊ณ , ์ง„์งœ ํ–‰ ๋‹จ์œ„๋กœ ์„ ํƒ์„ ํ•œ๋‹ค.

์ด๊ฒƒ๋„ ํ–‰ ๊ฐœ์ˆ˜๊ฐ€ ์ผ์ •ํ•˜์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์€ ๋งˆ์ฐฌ๊ฐ€์ง€๊ณ 


SYSTEM SAMPLE์— ๋น„ํ•ด์„œ ์„ฑ๋Šฅ์€ ๋งค์šฐ ๋А๋ฆฐ ํŽธ์ด๋‹ค.
๋Œ€์‹  ๋žœ๋ค ๋ถ„ํฌ๋„๊ฐ€ ๋” ์ข‹๋‹ค๋Š”๊ฒŒ ์žฅ์ ์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  REPEATABLE ์ ˆ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋žœ๋ค ์ƒ˜ํ”Œ๋ง์— ๋Œ€ํ•ด์„œ, ์‹œ๋“œ๊ฐ’์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
๊ฐ™์€ ์‹œ๋“œ๊ฐ’์ด ์ง€์ •๋˜๋ฉด ๊ฐ™์€ ํ–‰์„ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋œ๋‹ค.

์ด๊ฑธ ์“ฐ๋ฉด ๋ถ„ํฌ๋ฅผ ํ†ต์ œํ•  ์ˆ˜ ์žˆ๋‹ค.




TABLESAMPLE์˜ ๋‹จ์ 

์ด๋ ‡๊ฒŒ๋งŒ ๋ณด๋ฉด ์ข‹์•„๋ณด์ด์ง€๋งŒ, ์ด๊ฒƒ๋„ ๋‹จ์ ์€ ์žˆ๋‹ค.

์œ ์˜ํ•  ์  ์ค‘ ํ•˜๋‚˜๋กœ๋Š”, WHERE ํ•„ํ„ฐ์™€ ์„ž์–ด์“ฐ๊ธฐ์— ์–ด๋ ค์šด ๋ถ€๋ถ„์ด ๋งŽ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
TABLESAMPLE ํ…Œ์ด๋ธ” ์Šค์บ” ๊ฑฐ์˜ ๋ฐ”๋กœ ์งํ›„์— ์‹คํ–‰๋œ๋‹ค. ๊ทธ๋ž˜์„œ ์ƒ˜ํ”Œ๋งํ•œ ์ดํ›„์— WHERE ํ•„ํ„ฐ๊ฐ€ ์‹คํ–‰๋˜๋Š”๋ฐ, ์›๋ณธ ํ…Œ์ด๋ธ”์— ๊ทธ ํ•„ํ„ฐ ์กฐ๊ฑด์˜ ๊ฐ’์ด ์žˆ๋”๋ผ๋„ ์ƒ˜ํ”Œ๋ง๋œ ์ดํ›„์— ์—†์œผ๋ฉด ๋„๋ฃจ๋ฌต์ธ ์…ˆ์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋‹น์—ฐํžˆ ์ธ๋ฑ์Šค ์Šค์บ”์˜ ํšจ๊ณผ๋ฅผ ๋ณผ ์ˆ˜๋„ ์—†๋‹ค.



์ฐธ์กฐ
https://stackoverflow.com/questions/8674718/best-way-to-select-random-rows-postgresql
https://medium.com/@seungwooyu2000kr/postgresql-tablesample-bernoulli%EB%8A%94-order-by-random-%EC%9D%98-%EB%8C%80%EC%B2%B4%EC%A0%9C%EA%B0%80-%EC%95%84%EB%8B%88%EB%8B%A4-5f50f3ea96a3
https://wiki.postgresql.org/wiki/TABLESAMPLE_Implementation
https://www.depesz.com/2007/09/16/my-thoughts-on-getting-random-row/