๋ค์๊ณผ ๊ฐ์ ์ํฉ์ด ์์ต๋๋ค. ๊ธฐ๋ณธ ํค๊ฐ ์๋ ํ ์ด๋ธ์ ๋๋ ์ผ๋ถ ๋ค๋ฅธ ๊ณ ์ ์ธ๋ฑ์ค๋ ๊ฐ๋ ์ผ๋ก ์ธํด ๊ธฐ์กด ๋ ์ฝ๋์ ์์ ํ ๋ณต์ ๊ฐ ํฌํจ๋ฉ๋๋ค.
์๋ฅผ ๋ค์ด COPY ์คํธ๋ฆผ์ ์ฌ์ฉํ์ฌ ์ฐ๋์ ๋ฉํธ๋ฆญ ๊ฐ์ด PostgreSQL์ ๊ธฐ๋ก๋ ํ ๊ฐ์์ค๋ฌ์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ์ฌ ์์ ํ ๋์ผํ ๋ฐ์ดํฐ ์ค ์ผ๋ถ๊ฐ ๋ค์ ๋์ฐฉํฉ๋๋ค.
๋ถํ์ํ ํด๋ก ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ ๊ฑฐํ๋ ๋ฐฉ๋ฒ์ ๋ฌด์์
๋๊น?
PK๊ฐ ๋์ฐ๋ฏธ๊ฐ ์๋ ๊ฒฝ์ฐ
๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ ์ ์ด์ ๊ทธ๋ฌํ ์ํฉ์ด ๋ฐ์ํ์ง ์๋๋ก ๋ฐฉ์งํ๋ ๊ฒ์ ๋๋ค. ์๋ฅผ ๋ค์ด ๊ธฐ๋ณธ ํค๋ฅผ ๊ตด๋ฆฝ๋๋ค. ๊ทธ๋ฌ๋ ์ ์ฅ๋ ๋ฐ์ดํฐ์ ์์ ๋๋ฆฌ์ง ์๊ณ ๋ ์ด๊ฒ์ด ํญ์ ๊ฐ๋ฅํ ๊ฒ์ ์๋๋๋ค.
์๋ฅผ ๋ค์ด ์์ค ์์คํ ์ ์ ํ๋๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ๋์ ์ ํ๋๋ณด๋ค ๋์ ๊ฒฝ์ฐ:
metric | ts | data
--------------------------------------------------
cpu.busy | 2019-12-20 00:00:00 | {"value" : 12.34}
cpu.busy | 2019-12-20 00:00:01 | {"value" : 10}
cpu.busy | 2019-12-20 00:00:01 | {"value" : 11.2}
cpu.busy | 2019-12-20 00:00:03 | {"value" : 15.7}
๋์น์ฑ์ จ๋์? 00:00:02 ๋์ ์นด์ดํธ๋ค์ด์ XNUMX์ด ์ ์ ts๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ธฐ๋ก๋์์ง๋ง ์ ํ๋ฆฌ์ผ์ด์ ๊ด์ ์์๋ ๊ฝค ์ ํจํ ์ํ๋ก ์ ์ง๋์์ต๋๋ค(๊ฒฐ๊ตญ ๋ฐ์ดํฐ ๊ฐ์ด ๋ค๋ฆ ๋๋ค!).
๋ฌผ๋ก ๋น์ ์ ๊ทธ๊ฒ์ ํ ์ ์์ต๋๋ค PK(๋ฏธํฐ๋ฒ, TS) - ํ์ง๋ง ์ ํจํ ๋ฐ์ดํฐ์ ๋ํ ์ฝ์ ์ถฉ๋์ด ๋ฐ์ํฉ๋๋ค.
ํ ์์๋ค PK(๋ฏธํฐ๋ฒ, TS, ๋ฐ์ดํฐ) -๊ทธ๋ฌ๋ ์ด๋ ๊ฒ ํ๋ฉด ๋ณผ๋ฅจ์ด ํฌ๊ฒ ์ฆ๊ฐํ๋ฏ๋ก ์ฌ์ฉํ์ง ์์ ๊ฒ์ ๋๋ค.
๋ฐ๋ผ์ ๊ฐ์ฅ ์ฌ๋ฐ๋ฅธ ์ต์ ์ ์ผ๋ฐ ๊ณ ์ ํ์ง ์์ ์ธ๋ฑ์ค๋ฅผ ๋ง๋๋ ๊ฒ์ ๋๋ค. (๋ฏธํฐ๋ฒ, TS) ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ฉด ์ฌํ์ ์ฒ๋ฆฌํฉ๋๋ค.
"ํด๋ก ์ ์์ด ์์๋์์ต๋๋ค"
์ด๋ค ์ฌ๊ณ ๊ฐ ๋ฐ์ํ์ฌ ์ด์ ํ ์ด๋ธ์์ ๋ณต์ ๊ธฐ๋ก์ ์ญ์ ํด์ผ ํฉ๋๋ค.
์๋ณธ ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ธ๋งํด ๋ณด๊ฒ ์ต๋๋ค.
CREATE TABLE tbl(k text, v integer);
INSERT INTO tbl
VALUES
('a', 1)
, ('a', 3)
, ('b', 2)
, ('b', 2) -- oops!
, ('c', 3)
, ('c', 3) -- oops!!
, ('c', 3) -- oops!!
, ('d', 4)
, ('e', 5)
;
์ฌ๊ธฐ์ ์์ด ์ธ๋ฒ ๋จ๋ฆฌ๊ณ Ctrl+V๊ฐ ๋ฉ์ท๋๋ฐ ์ง๊ธ์...
๋จผ์ ํ ์ด๋ธ์ด ๋งค์ฐ ํด ์ ์์ผ๋ฏ๋ก ๋ชจ๋ ํด๋ก ์ ์ฐพ์ ํ์ ๋ฌธ์ ๊ทธ๋๋ก "์๊ฐ๋ฝ์ ์ฐ๋ฌ" ์ญ์ ํ๋ ๊ฒ์ด ์ข์ต๋๋ค. ํน์ ๊ธฐ๋ก์ ์ฌ๊ฒ์ํ์ง ์๊ณ .
๊ทธ๋ฆฌ๊ณ ๊ทธ๋ฐ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค - ์ด๊ฒ์
์ฆ, ์ฐ์ ํ ์ด๋ธ ํ์ ์ ์ฒด ๋ด์ฉ์ ๋ํ ๋งฅ๋ฝ์์ ๋ ์ฝ๋์ ctid๋ฅผ ์์งํด์ผ ํฉ๋๋ค. ๊ฐ์ฅ ๊ฐ๋จํ ์ต์ ์ ์ ์ฒด ์ค์ ํ ์คํธ๋ก ๋ณํํ๋ ๊ฒ์ ๋๋ค.
SELECT
T::text
, array_agg(ctid) ctids
FROM
tbl T
GROUP BY
1;
t | ctids
---------------------------------
(e,5) | {"(0,9)"}
(d,4) | {"(0,8)"}
(c,3) | {"(0,5)","(0,6)","(0,7)"}
(b,2) | {"(0,3)","(0,4)"}
(a,3) | {"(0,2)"}
(a,1) | {"(0,1)"}
์ ์บ์คํ ์ด ๊ฐ๋ฅํ๊ฐ์?์์น์ ์ผ๋ก ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ๊ฐ๋ฅํฉ๋๋ค. ์ด ํ ์ด๋ธ์ ํ๋๋ฅผ ์ฌ์ฉํ๊ธฐ ์์ํ ๋๊น์ง ํญ๋ฑ ์ฐ์ฐ์๊ฐ ์๋ ์ ํ:
CREATE TABLE tbl(k text, v integer, x point);
SELECT
array_agg(ctid) ctids
FROM
tbl T
GROUP BY
T;
-- ERROR: could not identify an equality operator for type tbl
์, ๋ฐฐ์ด์ ํญ๋ชฉ์ด ๋ ๊ฐ ์ด์ ์์ผ๋ฉด ๋ชจ๋ ํด๋ก ์ด๋ผ๋ ๊ฒ์ ์ฆ์ ์ ์ ์์ต๋๋ค. ๊ทธ๋ฅ ๋์:
SELECT
unnest(ctids[2:])
FROM
(
SELECT
array_agg(ctid) ctids
FROM
tbl T
GROUP BY
T::text
) T;
unnest
------
(0,6)
(0,7)
(0,4)
์งง๊ฒ ์ฐ๊ณ ์ถ์ ๋ถ๋ค์๋ค์๊ณผ ๊ฐ์ด ์์ฑํ ์๋ ์์ต๋๋ค.
SELECT
unnest((array_agg(ctid))[2:])
FROM
tbl T
GROUP BY
T::text;
์ง๋ ฌํ๋ ๋ฌธ์์ด์ ๊ฐ ์์ฒด๋ ์ฐ๋ฆฌ์๊ฒ ํฅ๋ฏธ๋กญ์ง ์๊ธฐ ๋๋ฌธ์ ํ์ ์ฟผ๋ฆฌ์ ๋ฐํ๋ ์ด์์ ํด๋น ๊ฐ์ ์ญ์ ํ์ต๋๋ค.
ํด์ผ ํ ์ผ์ด ์กฐ๊ธ ๋จ์์ต๋๋ค. DELETE๊ฐ ์ฐ๋ฆฌ๊ฐ ๋ฐ์ ์ธํธ๋ฅผ ์ฌ์ฉํ๋๋ก ํ์ธ์.
DELETE FROM
tbl
WHERE
ctid = ANY(ARRAY(
SELECT
unnest(ctids[2:])
FROM
(
SELECT
array_agg(ctid) ctids
FROM
tbl T
GROUP BY
T::text
) T
)::tid[]);
์ค์ค๋ก ํ์ธํด ๋ด ์๋ค:
์, ๋ชจ๋ ๊ฒ์ด ์ ํํฉ๋๋ค. ์ ์ฒด ํ ์ด๋ธ์ ์ ์ผํ Seq ์ค์บ์ ์ํด 3๊ฐ์ ๋ ์ฝ๋๊ฐ ์ ํ๋์์ผ๋ฉฐ ๋ฐ์ดํฐ ๊ฒ์์๋ ์ญ์ ๋ ธ๋๊ฐ ์ฌ์ฉ๋์์ต๋๋ค. Tid ์ค์บ์ ์ฌ์ฉํ ๋จ์ผ ํจ์ค:
-> Tid Scan on tbl (actual time=0.050..0.051 rows=3 loops=1)
TID Cond: (ctid = ANY ($0))
๋ง์ ๊ธฐ๋ก์ ์ง์ ๋ค๋ฉด,
๋ ํฐ ํ ์ด๋ธ๊ณผ ๋ ๋ง์ ์ค๋ณต ํญ๋ชฉ์ด ์๋์ง ํ์ธํด ๋ณด๊ฒ ์ต๋๋ค.
TRUNCATE TABLE tbl;
INSERT INTO tbl
SELECT
chr(ascii('a'::text) + (random() * 26)::integer) k -- a..z
, (random() * 100)::integer v -- 0..99
FROM
generate_series(1, 10000) i;
๋ฐ๋ผ์ ์ด ๋ฐฉ๋ฒ์ ์ฑ๊ณต์ ์ผ๋ก ์๋ํ์ง๋ง ์ฃผ์ํด์ ์ฌ์ฉํด์ผ ํฉ๋๋ค. ์ญ์ ๋๋ ๋ชจ๋ ๊ธฐ๋ก์ ๋ํด Tid Scan์์ ์ฝ์ ๋ฐ์ดํฐ ํ์ด์ง๊ฐ ํ๋, ์ญ์ ์์ ํ๋์ ๋ฐ์ดํฐ ํ์ด์ง๊ฐ ์๊ธฐ ๋๋ฌธ์
๋๋ค.
์ถ์ฒ : habr.com