โ ๊ธฐ์ ์ด ๋ณด์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ค๊ณ ์๊ฐํ๋ค๋ฉด, ๋ฌธ์ ๋, ๊ธฐ์ ์์ฒด๋ ์ดํดํ์ง ๋ชปํ ๊ฒ์ด๋ค. โ
- Bruce Schneier
๋ณด์ ๊ด๋ จ ํ์ฌ์ธ Counterpane Internet Security์ ์ค๋ฆฝ์

EXISTS ์ฐ์ฐ์
์๋ธ์ฟผ๋ฆฌ๊ฐ ๋ฐํ๋๋ ๊ฒฐ๊ณผ๊ฐ์ด ์๋์ง๋ฅผ ์กฐ์ฌํ๋ค.
๋จ์ง ๋ฐํ๋ ํ์ด ์๋์ง ์๋์ง๋ง ๋ณด๊ณ ๊ฐ์ด ์์ผ๋ฉด ์ฐธ ์์ผ๋ฉด ๊ฑฐ์ง์ ๋ฐํํ๋ค.
- ํ ํ ์ด๋ธ์ด ๋ค๋ฅธ ํ ์ด๋ธ๊ณผ ์ธ๋ํค(FK)์ ๊ฐ์ ๊ด๊ณ๊ฐ ์์ ๋ ์ ์ฉ
- ์กฐ๊ฑด์ ํด๋นํ๋ ROW์ ์กด์ฌ ์ ๋ฌด์ ์ดํ ๋ ์ํํ์ง ์์ (์ง์ฐ ํ๊ฐ ์๋ฆฌ ์ด๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ์ด ์ข๋ค)
- ์ผ๋ฐ์ ์ผ๋ก SELECT์ ๊น์ง ๊ฐ์ง ์๊ธฐ์ IN์ ๋นํด ์๋๋ ์ฑ๋ฅ๋ฉด์์ ๋ ์ข์
- ๋ฐ๋๋ก ์กฐ๊ฑด์ ๋ง์ง ์๋ ROW๋ง ์ถ์ถํ๊ณ ์ถ์ผ๋ฉด NOT EXISTS
- ์ฟผ๋ฆฌ ์์ : ๋ฉ์ธ ์ฟผ๋ฆฌ โ EXISTS ์ฟผ๋ฆฌ


Q. ์ฃผ๋ฌธํ ์ ์ด ์๋(์ฃผ๋ฌธ์ด ์กด์ฌํ๋) ์ฌ์ฉ์๋ฅผ ์๊ณ ์ถ์ ๊ฒฝ์ฐ
SELECT * FROM customers
WHERE EXISTS (
SELECT *
FROM orders
WHERE orders.c_id = customers.c_id
);

์๋ธ์ฟผ๋ฆฌ ๋ด์์ ๋ถ๋ชจ์ฟผ๋ฆฌ์ ํ๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
๋ง์น JAVA์ ์์ํด๋์ค๊ฐ ๋ถ๋ชจํด๋์ค์ ์ธ์คํด์ค๋ฅผ ์ฌ์ฉํ ์ ์๋ ๊ฒ์ฒ๋ผ ์์ ๊ฐ๋ ์ด๋ผ ์๊ฐํ๋ฉด ๋๋ค. ์ฐ๊ด ์๋ธ์ฟผ๋ฆฌ๋ผ๊ณ ํ๋ค.
์ด์ฒ๋ผ ์๋ธ์ฟผ๋ฆฌ์์ ๋ฉ์ธ์ฟผ๋ฆฌ ํ ์ด๋ธ์ ํ์ฉํ๋ ํํ๋ฅผ ์ฐ๊ด ์๋ธ์ฟผ๋ฆฌ๋ผ๊ณ ํ๋ค.
EXISTS ๋ค์์ผ๋ก ์ค๋ SELECT์์ * ๋์ ์๋ฌด๊ฑฐ๋(1, โaaโ, โฆ) ์ ๋ ฅํด๋ ์๊ด์๋ค.
EXISTS๋ ์กฐ๊ฑด์ด ๋ง๋ ์ง์ ๋ํ TRUE / FALSE๋ง ํ์ธํ๊ธฐ ๋๋ฌธ์ด๋ค. ๋ง์กฑํ๋ ๊ฒฐ๊ณผ๊ฐ ์ต์ ํ๋๊ฐ ๋์ค๋ฉด ๋ฐ๋ก TRUE๋ก ํ๋จํ๋ค.
์ฆ customers ํ ์ด๋ธ์ c_id๋ฅผ EXISTS ์๋ธ์ฟผ๋ฆฌ์ ๋์ ํ์ ๋ ๊ฐ์ด ์กด์ฌํ๋ฉด, ํด๋น ๋ ์ฝ๋๋ค์ ๋ชจ์ ๋์ด๋ค ๋ผ๊ณ ์ดํดํ๋ฉด ๋๋ค.
NOT EXISTS ์ฐ์ฐ์
orders ํ ์ด๋ธ์๋ customers ํ ์ด๋ธ์ ์กด์ฌํ์ง ์๋ ๊ณ ๊ฐ ID๊ฐ ์กด์ฌํ๋ค.
์ด ํ๋๋ NOT EXISTS๋ฅผ ์ฌ์ฉํ๋ฉด ์์๋ผ ์ ์๋ค.
์ฆ, ์กฐ๊ฑด์ ๋ง์ง์๋ ๋ ์ฝ๋๋ง ์ถ์ถํ๋ ์ต์ ์ด๋ผ ๋ณผ ์ ์๋ค.
SELECT *
FROM orders
WHERE NOT EXISTS (SELECT * FROM customers WHERE customers.c_id = orders.c_id);

EXISTS vs IN ์ฐ์ฐ์ ์ฐจ์ด
EXISTS์ IN์ ๋๋ค WHERE์ ์์ ์ฌ์ฉ๋๋ฉฐ, ์กฐ๊ฑด์ ๋ฐ๋ผ ๋ฐ์ดํฐ๋ฅผ ๊ฑธ๋ฌ๋ด์ด ๊ฒฐ๊ณผ๋ฅผ ์กฐํํ ๋ ์ฌ์ฉ๋๋ ๊ณตํต์ ์ ๊ฐ์ง๊ณ ์๋ค.
์๋ธ์ฟผ๋ฆฌ IN ์ฐ์ฐ์
- ์งํฉ ๋ด๋ถ์ ๊ฐ์ด ์กด์ฌํ๋์ง ์ฌ๋ถ ํ์ธ
- ์กฐ๊ฑด์ ํด๋นํ๋ ROW์ ์ปฌ๋ผ ๋น๊ตํ์ฌ ์ฒดํฌ
- SELECT์ ์์ ์กฐํํ ์ปฌ๋ผ ๊ฐ์ผ๋ก ๋น๊ตํ์ฌ EXISTS์ ๋นํด ์ฑ๋ฅ ๋จ์ด์ง
- ์ฟผ๋ฆฌ ์์ : IN ์ฟผ๋ฆฌ โ ๋ฉ์ธ ์ฟผ๋ฆฌ
-- IN
SELECT *
FROM customers
WHERE c_id IN ( SELECT DISTINCT c_id FROM orders);

EXISTS vs JOIN ์ฑ๋ฅ ๋น๊ต
EXISTS ๋์ JOIN์ ํ์ฉํ์ฌ ์ญ์ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์๋ ์๋ค.
๋ค์๊ณผ ๊ฐ์ด ์ํ ํ ์ด๋ธ์ด ์๋ค๊ณ ๊ฐ์ ํ์

INNER JOIN
select dept_id, dept_name, emp_id
from ๋ถ์ inner join ์ฌ์
on ๋ถ์.dept_id = ์ฌ์.dept_id

INNER JOIN (์ค๋ณต ์ ๊ฑฐ)
๋จ์ํ ์กฐ์ธํ๋๋ ์ค๋ณต๋ ๋ ์ฝ๋๋ค์ด ๋์จ๋ค. DISTINCT๋ก ์ค๋ณต์ ์ ๊ฑฐํ๋ค.
select distinct dept_id, dept_name, emp_id
from ๋ถ์ inner join ์ฌ์
on ๋ถ์.dept_id = ์ฌ์.dept_id

ํ์ง๋ง ์ด๋ ๊ฒ ํ๋ฉด ์์ ๋ฐ์ดํฐ์ DISTINCT ์ฐ์ฐ ์์ฒด๊ฐ ๊ฝค๋ ๋ฌด๊ฑฐ์ด ์์ ์ด๋ฉฐ, ์ถ๋ ฅ๊ฒฐ๊ณผ๋ณด๋ค ๋ง์ ์์๋ฐ์ดํฐ๊ฐ ์์ฑ๋๊ณ ๋๊ณ ๊ทธ ๋ ์ฝ๋๋ค์ ๋ํด JOIN ์ฐ์ฐ์ ํด์ผ๋๋ ๋จ์ ์ ์๊ณ ์๋ค.
์๋ธ์ฟผ๋ฆฌ EXISTS
EXISTS์ ๊ฒฝ์ฐ๋ inner query๋ฅผ ๋ง์กฑํ๋ ๋ ์ฝ๋๋ฅผ ์ฒ์ ๋ง๋๋ ์๊ฐ EXISTS๊ฐ true์ด๋ฏ๋ก inner query๋ฅผ ๋ ์ด์ ํ๊ฐ ํ์ง ์๋๋ค. (์ง์ฐ ํ๊ฐ ์๋ฆฌ)
์ด ์ ์ด INNER JOIN๊ณผ EXISTS์ ํฐ ์ฐจ์ด์ด๋ฉฐ ์ฑ๋ฅ์ ์ฐจ์ด๋ฅผ ๋ณด์ธ๋ค.
select dept_id, dept_name
from ๋ถ์
where exists ( select 1 from ์ฌ์ where ์ฌ์.dept_id = ๋ถ์.dept_id )
-- ๋ถ์์ dept_id๊ฐ ์ฌ์์ dept_id์ 1๊ฐ๋ผ๋ ์กด์ฌํ๋ฉด true
-- ๋ฐ๋ผ์ dept_id๊ฐ ๋์ผํ ์ฌ์ ๋ ์ฝ๋๋ฅผ ๋ง๋๋ฉด ๋์ด์ ํ์ํ ํ์๊ฐ ์์ด์ง๋ค. (์ง์ฐ ํ๊ฐ)

ํ์์๋ ์๋ธ ์ฟผ๋ฆฌ ๋ณด๋ค๋ JOIN์ด ์๋๊ฐ ๋น ๋ฅด๊ฒ ์ง๋ง, ๋ง์ผ ์ ์ฒ๋ผ ์ค๋ณต๋ ๋ฐ์ดํฐ๊ฐ ๋ง์ ๊ฒฝ์ฐ ์ง์ฐ ํ๊ฐ ์๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ์๋ธ ์ฟผ๋ฆฌ EXISTS ๋ฌธ์ด ๋น ๋ฅผ์๋ ์๋ค.
# ์ฐธ๊ณ ์๋ฃ
http://jason-heo.github.io/mysql/2014/05/30/mysql-inner-join-vs-exists.html
์ด ๊ธ์ด ์ข์ผ์ จ๋ค๋ฉด ๊ตฌ๋ & ์ข์์
์ฌ๋ฌ๋ถ์ ๊ตฌ๋
๊ณผ ์ข์์๋
์ ์์๊ฒ ํฐ ํ์ด ๋ฉ๋๋ค.