์ค๋๋ SQL์๋ ๋ณต์กํ ์ฌ๋ก์ ์ ๊ตํ ์๊ณ ๋ฆฌ์ฆ์ด ์์ต๋๋ค. Captain Obvious ์์ค์์๋ ๋ชจ๋ ๊ฒ์ด ๋งค์ฐ ๊ฐ๋จํด์ง๋๋ค. ํด๋ด ์๋ค. ์ด๋ฒคํธ ๋ ์ง์คํธ๋ฆฌ ๋ณด๊ธฐ ์๊ฐ๋ณ๋ก ์ ๋ ฌํ์ต๋๋ค.
์ฆ, ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ธฐํธ๊ฐ ์์ต๋๋ค. events
, ๊ทธ๋ฆฌ๊ณ ๊ทธ๋
๋ ๋ฐญ์ ๊ฐ๊ณ ์์ด์ ts
- ์ด๋ฌํ ๊ธฐ๋ก์ ์์๋๋ก ํ์ํ๋ ค๋ ์ ํํ ์๊ฐ:
CREATE TABLE events(
id
serial
PRIMARY KEY
, ts
timestamp
, data
json
);
CREATE INDEX ON events(ts DESC);
๊ฑฐ๊ธฐ์๋ XNUMX๊ฐ์ ๋ ์ฝ๋๊ฐ ์์ ๊ฒ์ด ๋ถ๋ช ํ๋ฏ๋ก ์ด๋ค ํํ์ ๋ ์ฝ๋๊ฐ ํ์ํฉ๋๋ค. ํ์ด์ง ํ์.
#0. โ๋๋ ์ฐ๋ฆฌ ์๋ง์ ํ์ด์์์โ
cur.execute("SELECT * FROM events;")
rows = cur.fetchall();
rows.sort(key=lambda row: row.ts, reverse=True);
limit = 26
print(rows[offset:offset+limit]);
๊ฑฐ์ ๋๋ด์ด ์๋๋๋ค. ๋๋ฌผ์ง๋ง ์ผ์์์ ๋ฐ๊ฒฌ๋ฉ๋๋ค. ๋๋ก๋ ORM์ผ๋ก ์์ ํ ํ SQL์ ์ฌ์ฉํ์ฌ "์ง์ " ์์ ์ผ๋ก ์ ํํ๋ ๊ฒ์ด ์ด๋ ค์ธ ์ ์์ต๋๋ค.
ํ์ง๋ง ๋ ์ผ๋ฐ์ ์ด๊ณ ๋ ๋ถ๋ช
ํ ๋ฌธ์ ๋ก ๋์ด๊ฐ๊ฒ ์ต๋๋ค.
#1. ์คํ์
SELECT
...
FROM
events
ORDER BY
ts DESC
LIMIT 26 OFFSET $1; -- 26 - ะทะฐะฟะธัะตะน ะฝะฐ ัััะฐะฝะธัะต, $1 - ะฝะฐัะฐะปะพ ัััะฐะฝะธัั
์ซ์ 26์ ์ด๋์์ ์์ต๋๊น? ์ด๋ ํ ํ๋ฉด์ ์ฑ์ฐ๋ ๋๋ต์ ์ธ ํญ๋ชฉ ์์ ๋๋ค. ๋ณด๋ค ์ ํํ๊ฒ๋ 25๊ฐ์ ํ์๋ ๋ ์ฝ๋์ 1์ ๋ํ ๊ฒ์ ๋๋ค. ์ด๋ ์ํ์ ์ต์ํ ๋ค๋ฅธ ํญ๋ชฉ์ด ๋ ์์ผ๋ฏ๋ก ๊ณ์ ์งํํ๋ ๊ฒ์ด ํฉ๋ฆฌ์ ์ด๋ผ๋ ์ ํธ์ ๋๋ค.
๋ฌผ๋ก ์ด ๊ฐ์ ์์ฒญ ๋ณธ๋ฌธ์ "๊ฟฐ์ด์ง" ์ ์์ผ๋ฉฐ ๋งค๊ฐ๋ณ์๋ฅผ ํตํด ์ ๋ฌ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ ์ด ๊ฒฝ์ฐ PostgreSQL ์ค์ผ์ค๋ฌ๋ ์๋์ ์ผ๋ก ์ ์ ์์ ๋ ์ฝ๋๊ฐ ์์ด์ผ ํ๋ค๋ ์ง์์ ์์กดํ ์ ์์ผ๋ฉฐ ์ฝ๊ฒ ๋นํจ์จ์ ์ธ ๊ณํ์ ์ ํํ ๊ฒ์ ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ธํฐํ์ด์ค์์ ๋ ์ง์คํธ๋ฆฌ ๋ณด๊ธฐ๋ ์๊ฐ์ "ํ์ด์ง" ๊ฐ ์ ํ์ผ๋ก ๊ตฌํ๋๋ฏ๋ก ์ค๋ซ๋์ ์๋ฌด๋ ์์ฌ์ค๋ฌ์ด ์ ์ ๋์น์ฑ์ง ๋ชปํฉ๋๋ค. ํธ์์ฑ์ ์ํด UI/UX๊ฐ ์ธํฐํ์ด์ค๋ฅผ "๋์๋ ์คํฌ๋กค"๋ก ๋ค์ ๋ง๋ค๊ธฐ๋ก ๊ฒฐ์ ํ ๋ฐ๋ก ๊ทธ ์๊ฐ๊น์ง ๋ง์ ๋๋ค. ์ฆ, ๋ชจ๋ ๋ ์ง์คํธ๋ฆฌ ํญ๋ชฉ์ ์ฌ์ฉ์๊ฐ ์์๋๋ก ์คํฌ๋กคํ ์ ์๋ ๋จ์ผ ๋ชฉ๋ก์ ๊ทธ๋ ค์ง๋๋ค.
๊ทธ๋์ ๋ค์ ํ
์คํธ์์ ๋น์ ์ ์กํ์ต๋๋ค. ๊ธฐ๋ก์ ๋ณต์ ๋ ์ง์คํธ๋ฆฌ์์. ์ด์ ๋ ํ
์ด๋ธ์ ์ผ๋ฐ ์ธ๋ฑ์ค๊ฐ ์๊ธฐ ๋๋ฌธ์
๋๋ค. (ts)
, ๊ทํ์ ์ฟผ๋ฆฌ๋ ๋ฌด์์ ์์กดํฉ๋๊น?
์ ํํ๋ ๋น์ ์ด ๊ทธ ์ ์ ๊ณ ๋ คํ์ง ์์๊ธฐ ๋๋ฌธ์
๋๋ค ts
๊ณ ์ ํค๊ฐ ์๋๋๋ค. ์ด ํ
์ด๋ธ์. ์ฌ์ค, ๊ทธ๋ฆฌ๊ณ ๊ทธ ๊ฐ์ ๊ณ ์ ํ์ง ์์ต๋๋ค, ์ค์ ์กฐ๊ฑด์ "์๊ฐ"๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก, ๋์ผํ ํค ๊ฐ์ ์ ๋ ฌํ๋ ํ๋ ์์ํฌ ๋ด์์ ์ต์ข
์์๊ฐ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ์ธ์ ํ ๋ ์ฟผ๋ฆฌ์ ๋์ผํ ๋ ์ฝ๋๊ฐ ํ์ด์ง์์ ํ์ด์ง๋ก ์ฝ๊ฒ "์ ํ"๋ฉ๋๋ค.
์ฌ์ค ์ฌ๊ธฐ์๋ ํจ์ฌ ๋ ๋์ ๋๊ธฐ ์ด๋ ค์ด ๋ ๋ฒ์งธ ๋ฌธ์ ๊ฐ ์จ๊ฒจ์ ธ ์์ต๋๋ค. ์ผ๋ถ ํญ๋ชฉ์ ํ์๋์ง ์์ต๋๋ค ์กฐ๊ธ๋! ๊ฒฐ๊ตญ "์ค๋ณต" ๊ธฐ๋ก์ด ๋ค๋ฅธ ์ฌ๋์ ์๋ฆฌ๋ฅผ ์ฐจ์งํ๊ฒ ๋ ๊ฒ์
๋๋ค. ์๋ฆ๋ค์ด ์ฌ์ง๊ณผ ํจ๊ป ์์ธํ ์ค๋ช
์ ๋ณด์ค ์ ์์ต๋๋ค
์ธ๋ฑ์ค ํ์ฅ
๊ตํํ ๊ฐ๋ฐ์๋ ์ธ๋ฑ์ค ํค๋ฅผ ๊ณ ์ ํ๊ฒ ๋ง๋ค์ด์ผ ํ๋ฉฐ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ ๋ถ๋ช ํ ๊ณ ์ ํ ํ๋๋ก ์ธ๋ฑ์ค ํค๋ฅผ ํ์ฅํ๋ ๊ฒ์ ๋๋ค. PK๋ ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์ ์ ํฉํฉ๋๋ค.
CREATE UNIQUE INDEX ON events(ts DESC, id DESC);
๊ทธ๋ฆฌ๊ณ ์์ฒญ์ ๋ค์๊ณผ ๊ฐ์ด ๋ณ๊ฒฝ๋ฉ๋๋ค.
SELECT
...
ORDER BY
ts DESC, id DESC
LIMIT 26 OFFSET $1;
#2. "์ปค์"๋ก ์ ํ
์ผ๋ง ํ DBA๊ฐ ๊ทํ์๊ฒ ์์ ๊ทํ์ ์์ฒญ์ "๊ธฐ๋ปํฉ๋๋ค"
SELECT
...
WHERE
(ts, id) < ($1, $2) -- ะฟะพัะปะตะดะฝะธะต ะฟะพะปััะตะฝะฝัะต ะฝะฐ ะฟัะตะดัะดััะตะผ ัะฐะณะต ะทะฝะฐัะตะฝะธั
ORDER BY
ts DESC, id DESC
LIMIT 26;
์ค๊ธฐ ์ ๊น์ง ์๋์ ํ์จ์ ์ฌ์ จ๋๋ฐ...
#์ผ. ์ธ๋ฑ์ค ์ฒญ์
์ด๋ ๋ ๋น์ ์ DBA๊ฐ ์ฝ์๊ธฐ ๋๋ฌธ์
๋๋ค. (ts DESC)
.
๊ทธ๋ฌ๋ ํ์ด์ง ์ฌ์ด์ ๋ ์ฝ๋๋ฅผ "์ ํ"ํ๋ ์ด๊ธฐ ๋ฌธ์ ๋ ์ด๋ป๊ฒ ์ฒ๋ฆฌํด์ผ ํ ๊น์?.. ๊ทธ๋ฆฌ๊ณ ๋ชจ๋ ๊ฒ์ด ๊ฐ๋จํฉ๋๋ค. ๋ ์ฝ๋ ์๊ฐ ๊ณ ์ ๋์ง ์์ ๋ธ๋ก์ ์ ํํด์ผ ํฉ๋๋ค!
์ผ๋ฐ์ ์ผ๋ก "์ ํํ 26"์ด ์๋๋ผ "26 ์ด์"์ ์ฝ๋ ๊ฒ์ ๋๊ฐ ๊ธ์งํฉ๋๊น? ์๋ฅผ ๋ค์ด, ๋ค์ ๋ธ๋ก์๋ ๋ค์์ด ์์ต๋๋ค. ๋ช
๋ฐฑํ ๋ค๋ฅธ ์๋ฏธ๋ฅผ ์ง๋ ๊ธฐ๋ก ts
- ๊ทธ๋ฌ๋ฉด ๋ธ๋ก ์ฌ์ด์ ๊ธฐ๋ก์ "์ ํ"ํ๋ ๋ฐ ๋ฌธ์ ๊ฐ ์์ ๊ฒ์
๋๋ค!
์ด๋ฅผ ๋ฌ์ฑํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
SELECT
...
WHERE
ts < $1 AND
ts >= coalesce((
SELECT
ts
FROM
events
WHERE
ts < $1
ORDER BY
ts DESC
LIMIT 1 OFFSET 25
), '-infinity')
ORDER BY
ts DESC;
์ฌ๊ธฐ์ ๋ฌด์จ ์ผ์ด ์ผ์ด๋๊ณ ์๋ ๊ฑธ๊น์?
- 25๊ฐ์ ๋ ์ฝ๋๋ฅผ "์๋๋ก" ๋จ๊ณํํ๊ณ "๊ฒฝ๊ณ" ๊ฐ์ ์ป์ต๋๋ค.
ts
. - ์ด๋ฏธ ์๋ฌด๊ฒ๋ ์์ผ๋ฉด NULL ๊ฐ์ ๋ค์์ผ๋ก ๋ฐ๊ฟ๋๋ค.
-infinity
. - ๋ฐ์ ๊ฐ ์ฌ์ด์์ ์ ์ฒด ๊ฐ ์ธ๊ทธ๋จผํธ๋ฅผ ๋บ๋๋ค.
ts
์ธํฐํ์ด์ค์์ ์ ๋ฌ๋ $1 ๋งค๊ฐ๋ณ์(์ด์ ์ "๋ง์ง๋ง" ๋ ๋๋ง๋ ๊ฐ)์ ๋๋ค. - 26๊ฐ ๋ฏธ๋ง์ ๋ ์ฝ๋๊ฐ ํฌํจ๋ ๋ธ๋ก์ด ๋ฐํ๋๋ฉด ์ด๊ฒ์ด ๋ง์ง๋ง ๋ธ๋ก์ ๋๋ค.
์๋๋ฉด ๊ฐ์ ์ฌ์ง:
์๋๋ฉด ์ง๊ธ ์ฐ๋ฆฌ๋ ์ํ์๋ ํน์ "์์"์ด ์์ต๋๋ค., ๊ทธ๋ฌ๋ฉด ์ด ์์ฒญ์ ๋ฐ๋ ๋ฐฉํฅ์ผ๋ก "ํ์ฅ"ํ๊ณ "์ฐธ์กฐ ์ง์ "์์ ์๋ฐฉํฅ(์๋์ชฝ๊ณผ ์์ชฝ ๋ชจ๋)์ผ๋ก ๋ฐ์ดํฐ ๋ธ๋ก์ ๋์ ๋ก๋๋ฅผ ๊ตฌํํ๋ ๊ฒ์ ๋ฐฉํดํ๋ ๊ฒ์ ์์ต๋๋ค.
์ฐธ๊ณ :
- ์, ์ด ๊ฒฝ์ฐ ์ธ๋ฑ์ค์ ๋ ๋ฒ ์ก์ธ์คํ์ง๋ง ๋ชจ๋ ๊ฒ์ด "์์ ํ ์ธ๋ฑ์ค ๊ธฐ์ค"์ ๋๋ค. ๋ฐ๋ผ์ ํ์ ์ฟผ๋ฆฌ์ ๊ฒฐ๊ณผ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. ํ๋์ ์ถ๊ฐ ์ธ๋ฑ์ค ์ ์ฉ ์ค์บ์.
- ์ด ๊ธฐ์ ์ ๊ฐ์ด ์์ ๋๋ง ์ฌ์ฉํ ์ ์๋ค๋ ๊ฒ์ ๋งค์ฐ ๋ถ๋ช
ํฉ๋๋ค.
ts
์ฐ์ฐํ๋ง ๊ฑด๋๊ฐ ์ ์๊ณ , ๊ทธ ์ค ๋ง์ง ์์ต๋๋ค. ์ผ๋ฐ์ ์ธ ์ฌ๋ก๊ฐ "00:00:00.000์ ๋ ์ฝ๋ ๋ฐฑ๋ง ๊ฐ"์ธ ๊ฒฝ์ฐ์๋ ์ด๋ ๊ฒ ํ๋ฉด ์ ๋ฉ๋๋ค. ๋ด ๋ง์, ๊ทธ๋ฐ ์ผ์ด ์ผ์ด๋๋๋ก ๋๋ฌ์๋ ์ ๋๋ค๋ ๊ฒ์ ๋๋ค. ํ์ง๋ง ์ด๋ฐ ์ผ์ด ๋ฐ์ํ๋ฉด ํ์ฅ ์ธ๋ฑ์ค๊ฐ ์๋ ์ต์ ์ ์ฌ์ฉํ์ธ์.
์ถ์ฒ : habr.com