[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/