[PostgreSQL] Partial Index
Partial ์ธ๋ฑ์ค๋ PostgreSQL์์ ์ ๊ณตํ๋ ๊ฐ๋ ฅํ ์ธ๋ฑ์ค์ ํ์ฅ๊ธฐ๋ฅ ์ค ํ๋๋ค.
์ธ๋ฑ์ค์ ๋ํด์ ํน์ ์กฐ๊ฑด์ ๋ถ์ฌํด์, ์กฐ๊ฑด์ ๋ถํฉํ๋ ๋ฐ์ดํฐ๋ง ์ธ๋ฑ์ค์ ํฌํจ๋๋๋ก ํ๋ ๊ฒ์ด๋ค.
๊ทธ๋์ ๋ถ๋ถ(Partial) ์ธ๋ฑ์ค๋ค.
Create Index ์ธ๋ฑ์ค๋ช
on ํ
์ด๋ธ๋ช
(์ปฌ๋ผ...) where ์กฐ๊ฑด์
์ ์กฐ๊ฑด์์ ํฌํจ๋๋ Query๋ ์ธ๋ฑ์ค์ ๊ฑธ๋ ค์ ์ ์ธ๋ฑ์ฑ๋๊ณ , ํฌํจ๋์ง ์๋ ๋ฐ์ดํฐ๋ ์ธ๋ฑ์ฑ์ด ๋์ง ์๋๋ค.
false์ธ ๋ฐ์ดํฐ๋ ์ ์ด๋ถํฐ ์ธ๋ฑ์ค ํธ๋ฆฌ์ ์ ์ฅ์ ํ์ง๋ ์๊ณ , ๊ทธ๋ ๊ธฐ ๋๋ฌธ์ SELECT ์ฟผ๋ฆฌ ํ๋ ๋์ค์ ์กฐ๊ฑด์ ๊ฑธ๋ ค์์ง ์๋ค๋ฉด ์ธ๋ฑ์ค ์ค์บ์ ์๋ํ์ง๋ ์๋ ๊ฒ์ด๋ค.
์ด ๊ธฐ๋ฅ์ ์ฅ์ ์, ์กฐ์ ํ๊ธฐ์ ๋ฐ๋ผ์ ์ธ๋ฑ์ค ์ ์ฅ๊ณต๊ฐ์ ๋ ์๋ ์ ์๊ณ , Update ์์ ์ธ๋ฑ์ค ์์ ๋น์ฉ๋ ์ค์ผ ์ ์๋ค๋ ๊ฒ์ด๋ค.
๊ทผ๋ฐ ์๋ง ์ด ์ด์ ๋ง์ผ๋ก ์ฐ๋ ์ฌ๋์ ๋ช ์์ ๊ฒ์ด๋ค.
์์ฉ: Partial Unique Index
์ฌ์ค ์ด ๊ธฐ๋ฅ์ ๊ฐ์ฅ ์ ์ฉํ ์์ฉ ๋ฐฉ๋ฒ์, ์กฐ๊ฑด์ ๋ฐ๋ฅธ ์ ํ์ Unique๋ฅผ ์ค์ ํ๋ ๊ฒ์ด๋ค.
์๋ฅผ ๋ค์ด, ์ด๋ฉ์ผ์ ์ ์ผํค๋ก ์ก๋ ๊ณ์ ์ ๋ณด ํ ์ด๋ธ์ด ์๋ค๊ณ ๊ฐ์ ํด๋ณด๊ฒ ๋ค.
Create Table "user" (
id SERIAL PRIMARY KEY,
email VARCHAR(100) NOT NULL,
password VARCHAR(200) NOT NULL,
name VARCHAR(100) NOT NULL,
leftAt TIMESTAMPTZ -- ํํด ์์
);
INSERT INTO "user" (email, password, name, leftAt) VALUES
('asdf@example.com', 'q1w2e3r4', 'John', NULL),
('qert@example.com', 'q1w2e3r4', 'Tom', NULL),
('foo.bar@example.com', 'q1w2e3r4', 'Anna', NULL),
('buldak@example.com', 'q1w2e3r4', 'Alice Four', NULL),
('gang@example.com', 'q1w2e3r4', 'jonathan', NULL),
('kimchi@example.com', 'q1w2e3r4', 'kim', NULL),
('do@example.com', 'q1w2e3r4', 'doe', NULL);

๋ปํ ๊ตฌ์ฑ์ด๋ค.
์ด๋ฉ์ผ์ด ์๊ณ , ํํด ์์ ์ ๊ธฐ๋กํ๋ leftat ํ๋๋ ์๋ค.
์ ๊ฒ null์ด ์๋๋ฉด ํํดํ ํ์์ธ ๊ฒ์ด๋ค.
์ฌ๊ธฐ์ ๋ํด์ ์ด๋ฉ์ผ ์ ์ฝ์ ๊ฑด๋ค๋ฉด, ๊ฐ์ฅ ๋จ์ํ๋ฉด์๋ ๊ฐ๋ ฅํ ๋ฐฉ๋ฒ์ Unique ์ธ๋ฑ์ค๋ฅผ ๊ฝ์๋ฒ๋ฆฌ๋ ๊ฒ์ด๋ค.
Create Unique Index email_unique on "user"(email);
INSERT INTO "user" (email, password, name, leftAt) VALUES
('asdf@example.com', 'q1w2e3r4', 'Other People', NULL);
์๋ฒ์๋ค๊ฐ ์ง์ ๊ตฌํํ๋ฉด ๋์์ฑ ๋ฌธ์ ๋ก ์ ์ผ์ฑ์ด ๊นจ์ง ํ๋ฅ ๋ ๋๊ณ , ๊ฐ๋ ฅํ ์ผ๊ด์ฑ์ ๋ณด์ฅํ๋ ค๋ฉด ๊ฒฐ๊ตญ์๋ ๋จ์ผ ๋ฝ์ด ํ์ํ๋ค.
๊ทผ๋ฐ RDB ์์ฒด๊ฐ ๊ฐ๋ ฅํ ์์์ฑ์ ๋ณด์ฅํ๋ ๋จ์ผ ์คํ ๋ฆฌ์ง์ด๋, ์ ์ผ์ฑ ๋ณด์ฅ์ ์ด๋งํผ ํจ์จ์ ์ด๊ณ ์๋ฒฝํ ์๋ฃจ์
์ ๊ฑฐ์ ์๋ค๊ณ ๋ด๋ ๋ ๊ฒ์ด๋ค.
ํ์ง๋ง ์ข ์์ฉ์ ํ๋ค๋ณด๋ฉด ๋ฌธ์ ๊ฐ ์๊ธธ ์ ์๋ค.
update "user"
set leftAt = NOW()
where email = 'asdf@example.com';
์๋ฅผ ๋ค๋ฉด, ํํดํ ํ์์ด ์์๋, ๋์ผํ ์ด๋ฉ์ผ๋ก ์ฌ๊ฐ์
์ ํ๊ณ ์ถ์ ์๋ ์๋ ๊ฒ์ด๋ค.
๊ทธ๋ผ ์ด๋ป๊ฒ ํด์ผํ ๊น?
email+leftat์ ๋ฌถ์ด์ Unique๋ฅผ ๋ง๋ ๋ค๊ณ ํด๋, null์ด ํฌํจ๋๋ฉด Unique ์ ์ฝ์์ ๋ฒ์ด๋๊ธฐ ๋๋ฌธ์ ์๊ตฌ์ฌํญ์ ๋ง์กฑํ ์ ์๋ค.
์ฌ๊ธฐ์ ๋ํด์ ๊ฐ์ฅ ๋ช
์พํ ๊ตฌํ ๋ฐฉ๋ฒ์ Partial Unique ์ธ๋ฑ์ค๋ก ๋ถ๋ถ์ ์ธ ์ ์ฝ์ ๊ฐํ๋ ๊ฒ์ด๋ค.
์๋ฅผ ๋ค๋ฉด, ์ด๋ฐ ์์ด๋ค.
Drop Index email_unique;
Create Unique Index email_unique on "user"(email) where leftAt IS NULL;

์ด๋ฌ๋ฉด leftAt IS NULL์ ๋ง์กฑํ๋ ๋ฐ์ดํฐ์ ๋ํด์๋ง email ์ ์ผ์ฑ์ ๋ณด์ฅํ๋๋ก ์ธ๋ฑ์ค๊ฐ ๊ตฌ์ฑ๋๋ค.
INSERT INTO "user" (email, password, name, leftAt) VALUES
('asdf@example.com', 'q1w2e3r4', 'Other People', NULL);
๊ทธ๋ฌ๋ฉด leftat=null์ด ์๋ ๋ฐ์ดํฐ๋ ์ ์ผ์ฑ ์ ์ฝ์์ ๋ฒ์ด๋๊ณ
๋ ๋ฃ์ผ๋ ค๊ณ ํ๋ฉด ์๋๋๋ก ์ ๋งํ ๊ฒ์ด๋ค.
์ธ๋ฑ์ฑ ๊ณ ๋ ค
partial index๋ ์ค์ ๋ก ๋ถ๋ถ์ ์ผ๋ก๋ง ์ธ๋ฑ์ค๊ฐ ์์ฑ๋๋๋งํผ, ๊ทธ ๋ถ๋ถ ์กฐ๊ฑด์ ์ผ์นํ์ง ์์ผ๋ฉด ์ธ๋ฑ์ค๋ฅผ ํ์ง ์๋๋ค.
ํ๋ฒ ์คํํด๋ณด์.
์ผ๋จ ๋ฐ์ดํฐ๊ฐ ๋ช๊ฐ ์ด์์ ๋์ด์ผ ์ธ๋ฑ์ค๋ก ํ๋์ ์ก๊ธฐ ๋๋ฌธ์, ์ฐ๋ ๊ธฐ ๋ฐ์ดํฐ๋ฅผ ์ ๋นํ ๋ฃ์ด์ค๋ค.
Insert Into "user"(email, password, name, leftAt)
select t.n::text, 'auto generated', 'auto', null from (
select generate_series(1, 10000) as n
) as t;

๊ทธ๋ฆฌ๊ณ ๊ทธ๋ฅ email๋ก๋ง ์กฐ๊ฑด์ ๊ฑธ๊ฑฐ๋

leftAt IS NOT NULL์ ๊ฑธ๋ฉด ์ธ๋ฑ์ค๋ฅผ ์ ๋ ํ์ง ์๋๋ค. ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ธ๋ฑ์ค๋ฅผ ํ๋ ค๋ฉด ๋ฌด์กฐ๊ฑด Partial Index์์ ์ ์๋ ์กฐ๊ฑด์ด ๋ช
์๋์ด์ผ๋ง ํ๋ค.
๊ทธ๋์ Partial Unique Index๋ก ์ ์ผ์ฑ์ ๊ตฌํํ๋ค๊ณ ํ๋๋ผ๋, ์ค์ง์ ์ผ๋ก ์ธ๋ฑ์ฑ์ ์ฌ์ฉํ ์ค์ ์ ์ฒด ๋ฒ์์ ์ธ๋ฑ์ค๋ ๋ฐ๋ก ๋ง๋ จํด์ฃผ๋ ํธ์ด ์ข๋ค.
์ฐธ์กฐ
https://medium.com/little-programming-joys/unique-partial-indexes-with-postgresql-86e137905c12