๐ฏ ๋ฌธ์
์ชฝ์งํจ ๊ธฐ๋ฅ ๊ฐ๋ฐ ํ ์ชฝ์ง ๋ชฉ๋ก์ ์กฐํ ํ ๋ ๋ฐ์ดํฐ๊ฐ ์ ์ ๋ ๋ฌธ์ ๋ฅผ ๋๋ผ์ง ๋ชป ํ๋๋ฐ, 10๋ง๊ฑด ์ด์ ๋ฐ์ดํฐ ์ฝ์ ํ ํ ์คํธ ํ์ ๋ ์กฐํ ์๋๊ฐ ๋๋ ค์ก๋ค. ์กฐํ ์๋๋ฅผ ๊ฐ์ ํด๋ณด์!! ๐
์ ์ฒด ์กฐํ ๊ฐ์ , ๊ฒ์ ๊ฐ์ -> ํ์ด์ง ๊ฐ์ ์ผ๋ก ์งํํจ.
๊ธํ๋ฉด ๊ฒฐ๋ก ๋ง ๋ณด๊ธฐ!!
๐ ํ๋ฉด (๋ณด๋ธ ์ชฝ์ง ๋ชฉ๋ก)
โ ํ์ด์ง ์ง์ ์ ์ต์ ์์ผ๋ก ์กฐํ.
โ ๊ฒ์(ํํฐ)์กฐ๊ฑด์ ๋ฐ๋ผ ์กฐํ.
โ ํ์ด์ง ์ด๋ ์ ํ ํ์ด์ง ๊ฐ์ ์ค์ ๋งํผ ๊ฐ์ ธ์ด.
๐ ์๋ ์ธก์ ๋ฐฉ๋ฒ
โ ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ๋๊ตฌ ๋คํธ์ํฌ ์๋ต์ ์ธก์
์กฐํ ๊ฐ์, ๊ฒ์ ์กฐ๊ฑด์ ์ค์ ํ ์ ์๋๋ฐ, ์กฐํ ๊ฐ์ 10๊ฐ ๊ณ ์ ํ๊ณ ์ ์ฒด ์กฐํ์ ์์ ์(๋ฐ์ ์ฌ๋) ๊ฒ์ ์๊ฐ์ ์ธก์ ํ๋ค.
- ๋ด๊ฐ ๋ณด๋ธ ์ชฝ์ง 10๋ง๊ฑด + ๋ค๋ฅธ ์ชฝ์ง x
- ๋ด๊ฐ ๋ณด๋ธ ์ชฝ์ง 20๋ง๊ฑด + ๋ค๋ฅธ ์ชฝ์ง 10๋ง๊ฑด
โ ์ฐธ๊ณ
- ๋ค๋ฅธ ์ชฝ์ง: ๋ค๋ฅธ ์ ์ ๊ฐ ๋ณด๋ธ ์ชฝ์ง๋ก ์กฐํํ๋ฉด์ ๋์ค์ง ์๋ ๋ฐ์ดํฐ (๋ฐ์ ์ ID๋ก ์กฐํ)
- ์ ์กฐ๊ฑด์์ ๊ฐ์๋ ์ ํํ 10๋ง๊ฑด x, 100๊ฐ ๋ฏธ๋ง์ ๋ฐ์ดํฐ๊ฐ ๋ ์์์ง๋ง ๋ฌด์ํ๋ค!! (ํ ์คํธ๋ฅผ ํผ์๋ง ํ ์ ์๋ ํ๊ฒฝ์ด ์๋๋ผ์..)
- ์๋๋ 2๊ฐ์ง ๊ฒฝ์ฐ์์ ์ธก์ ํ์ง ๋ชป ํ๊ฑฐ๋ ์บก์ณ๋ฅผ ๋ชป ํ ๊ฒ๋ ์๋ค. ๐
โ app์ ๋ฐ์ ์ DBeaver ํด์์ ์ฟผ๋ฆฌ ์๋ ๋น๊ต
SET profiling = 1;
SHOW PROFILES;
์ ํ๋ฆฌ์ผ์ด์ ์์ ํ์ด์ง ๋ก๋, ๊ฒ์ ์
์กฐ๊ฑด์ ๋ง๋ ๋ฐ์ดํฐ ๊ฐ์ + ์ค์ ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๋ ์ฟผ๋ฆฌ 2๊ฐ๊ฐ ์คํ๋๋๋ฐ
๋ํผ ํด์์ ์ฟผ๋ฆฌ 2๊ฐ ๊ฐ๊ฐ ์คํ์๊ฐ ์ธก์ ํด์ ๋ํ ๊ฒ = ๊ฐ๋ฐ์ ๋๊ตฌ ์๋ต ์๊ฐ ์ผ์ถ ์ผ์นํ๋ค.
- ์ธก์ ์์ (๋ฐ์ดํฐ: ๋ณด๋ธ ์ชฝ์ง 20๋ง๊ฑด + ๋ค๋ฅธ ์ชฝ์ง 10๋ง๊ฑด)
โ 1. Exists ์ฌ์ฉ
โ 1-1. ์์ ์ ๊ฒ์ ๊ฐ์ - 3.3s
SELECT COUNT(DISTINCT n.note_id)
FROM notes n
LEFT JOIN note_trans_mgmt ntm ON n.note_id = ntm.note_id AND ntm.trans_type = "1" AND ntm.use_yn = "Y"
LEFT JOIN note_trans_mgmt ntm2 ON n.note_id = ntm2.note_id AND ntm2.trans_type = '2'
WHERE n.regt_id = 'user1'
AND EXISTS (
SELECT 1 FROM users u_sub
WHERE u_sub.user_id = ntm2.user_id
AND u_sub.user_nm_kr LIKE '%์ฉ%'
)
โ 1.2 ์์ ์ ๊ฒ์ - 7.13s
SELECT
n.note_id, n.title, n.content, n.regt_id, n.regt_dt
, ntm.trans_id, ntm.trans_type, ntm.read_yn, COUNT(nam.attach_id) as attach_cnt
, GROUP_CONCAT(DISTINCT u2.user_nm_kr) AS recv_nms
FROM notes n
LEFT JOIN note_trans_mgmt ntm ON n.note_id = ntm.note_id AND ntm.trans_type = "1" AND ntm.use_yn = "Y"
LEFT JOIN note_attach_mgmt nam ON n.note_id = nam.attach_id
LEFT JOIN note_trans_mgmt ntm2 ON n.note_id = ntm2.note_id AND ntm2.trans_type = '2'
LEFT JOIN users u2 ON ntm2.user_id = u2.user_id
WHERE n.regt_id = 'user1'
AND EXISTS (
SELECT 1 FROM users u_sub
WHERE u_sub.user_id = ntm2.user_id
AND u_sub.user_nm_kr LIKE '%์ฉ%'
)
GROUP BY n.note_id
ORDER BY n.note_id desc
โ 2. Exists ๋ฏธ์ฌ์ฉ
โ 2-1. ์์ ์ ๊ฒ์ - 5.1s
SELECT COUNT(DISTINCT n.note_id)
FROM notes n
LEFT JOIN note_trans_mgmt ntm ON n.note_id = ntm.note_id AND ntm.trans_type = "1" AND ntm.use_yn = "Y"
LEFT JOIN note_trans_mgmt ntm2 ON n.note_id = ntm2.note_id AND ntm2.trans_type = '2'
LEFT JOIN users u2 ON ntm2.user_id = u2.user_id
WHERE n.regt_id = 'user1'
AND u2.user_nm_kr LIKE '%์ฉ%'
โ 2.2 ์์ ์ ๊ฒ์ - 9.2s
SELECT
n.note_id, n.title, n.content, n.regt_id, n.regt_dt
, ntm.trans_id, ntm.trans_type, ntm.read_yn, COUNT(nam.attach_id) as attach_cnt
, GROUP_CONCAT(DISTINCT u2.user_nm_kr) AS recv_nms
FROM notes n
LEFT JOIN note_trans_mgmt ntm ON n.note_id = ntm.note_id AND ntm.trans_type = "1" AND ntm.use_yn = "Y"
LEFT JOIN note_attach_mgmt nam ON n.note_id = nam.attach_id
LEFT JOIN note_trans_mgmt ntm2 ON n.note_id = ntm2.note_id AND ntm2.trans_type = '2'
LEFT JOIN users u2 ON ntm2.user_id = u2.user_id
WHERE n.regt_id = 'user1'
AND u2.user_nm_kr LIKE '%์ฉ%'
GROUP BY n.note_id
ORDER BY n.note_id desc
๐ ์กฐํ ์๋ ๊ฐ์ ๊ณผ์
โ 1. ์ด๊ธฐ ์ฟผ๋ฆฌ (GROUP_CONCAT, LEFT JOIN, ์๋ธ์ฟผ๋ฆฌ ์ฌ์ฉ)
๐น ์กฐํ ์๋
- (๋ณด๋ธ ์ชฝ์ง 10๋ง๊ฑด + ๋ค๋ฅธ ์ชฝ์ง x) ์ ์ฒด: 17.71s
- (๋ณด๋ธ ์ชฝ์ง 20๋ง๊ฑด + ๋ค๋ฅธ ์ชฝ์ง 10๋ง๊ฑด) ์ ์ฒด**: 38.83s**
๐น ๋ฌธ์ ์
GROUP_CONCAT, LEFT JOIN๊ณผ ์๋ธ์ฟผ๋ฆฌ ๋ค์ค ์ฌ์ฉ์ผ๋ก ์ธํด ๋ฐ์ดํฐ๊ฐ ๋ง์์ง์๋ก ์ ํ์ ์ผ๋ก ์ฑ๋ฅ ์ ํ ๋ฐ์
๐น ์ด๊ธฐ ์ฟผ๋ฆฌ
<!-- ๋ณด๋ธ ์ชฝ์ง ๊ฐ์ -->
<select id="selectNoteByRegtIdTotalCnt">
SELECT COUNT(DISTINCT n.note_id)
FROM notes n
LEFT JOIN note_trans_mgmt ntm ON n.note_id = ntm.note_id
LEFT JOIN (
SELECT
n2.note_id,
GROUP_CONCAT(ntm2.user_id) AS recv_ids,
GROUP_CONCAT(u2.user_nm_kr) AS recv_nms
FROM
notes n2
LEFT JOIN
note_trans_mgmt ntm2 ON ntm2.note_id = n2.note_id AND ntm2.trans_type = '2'
LEFT JOIN users u2
ON ntm2.user_id = u2.user_id
GROUP BY
n2.note_id
) AS recvs ON n.note_id = recvs.note_id
WHERE n.regt_id = #{regtId} AND ntm.trans_type = "1" AND ntm.use_yn = "Y"
<if test="keyword != null and keyword != ''">
<choose>
<when test="searchOption == 'recv'">
AND LOWER(recvs.recv_nms) LIKE CONCAT('%', LOWER(#{keyword}), '%')
</when>
<when test="searchOption == 'titl'">
AND LOWER(n.title) LIKE CONCAT('%', LOWER(#{keyword}), '%')
</when>
<when test="searchOption == 'cont'">
AND LOWER(n.content) LIKE CONCAT('%', LOWER(#{keyword}), '%')
</when>
<otherwise>
AND (
LOWER(recvs.recv_nms) LIKE CONCAT('%', LOWER(#{keyword}), '%')
OR LOWER(n.title) LIKE CONCAT('%', LOWER(#{keyword}), '%')
OR LOWER(n.content) LIKE CONCAT('%', LOWER(#{keyword}), '%')
)
</otherwise>
</choose>
</if>
</select>
<!-- ๋ณด๋ธ ์ชฝ์ง -->
<select id="selectNoteListByRegtId">
SELECT
n.note_id, n.title, n.content, n.regt_id, n.regt_dt
, tu.user_nm_kr as userNm, ntm.trans_id, ntm.trans_type, ntm.read_yn
, COUNT(nam.attach_id) as attach_cnt
, recvs.recv_ids, recvs.recv_nms
FROM notes n
LEFT JOIN note_trans_mgmt ntm ON n.note_id = ntm.note_id
LEFT JOIN note_attach_mgmt nam ON n.note_id = nam.attach_id
LEFT JOIN users tu ON n.regt_id = tu.user_id
LEFT JOIN (
SELECT
n2.note_id,
GROUP_CONCAT(ntm2.user_id) AS recv_ids,
GROUP_CONCAT(u2.user_nm_kr) AS recv_nms
FROM
notes n2
LEFT JOIN
note_trans_mgmt ntm2 ON ntm2.note_id = n2.note_id AND ntm2.trans_type = '2'
LEFT JOIN users u2
ON ntm2.user_id = u2.user_id
WHERE n2.regt_id = #{regtId}
GROUP BY
n2.note_id
) AS recvs ON n.note_id = recvs.note_id
WHERE n.regt_id = #{regtId} AND ntm.trans_type = "1" AND ntm.use_yn = "Y"
<if test="keyword != null and keyword != ''">
<choose>
<when test="searchOption == 'recv'">
AND LOWER(recvs.recv_nms) LIKE CONCAT('%', LOWER(#{keyword}), '%')
</when>
<when test="searchOption == 'titl'">
AND LOWER(n.title) LIKE CONCAT('%', LOWER(#{keyword}), '%')
</when>
<when test="searchOption == 'cont'">
AND LOWER(n.content) LIKE CONCAT('%', LOWER(#{keyword}), '%')
</when>
<otherwise>
AND (
LOWER(recvs.recv_nms) LIKE CONCAT('%', LOWER(#{keyword}), '%')
OR LOWER(n.title) LIKE CONCAT('%', LOWER(#{keyword}), '%')
OR LOWER(n.content) LIKE CONCAT('%', LOWER(#{keyword}), '%')
)
</otherwise>
</choose>
</if>
GROUP BY n.note_id
ORDER BY n.note_id DESC
LIMIT #{pageSize} OFFSET #{startIndex}
</select>
โ 2. ์๋ธ์ฟผ๋ฆฌ ์ ๊ฑฐ
๐น ๊ฐ์
- ์๋ธ์ฟผ๋ฆฌ (recvs) ๋ฅผ ์ ๊ฑฐํ๊ณ , tbn_noterecvmgmt ์ ๋ฉ์ธ ์ฟผ๋ฆฌ์ ์ง์ JOIN ํ๋ ๋ฐฉ์์ผ๋ก ๋ณ๊ฒฝ. -> ๋ถํ์ํ ์์ ํ ์ด๋ธ ์์ฑ ์ ๊ฑฐ
- ๋ฐ์ดํฐ ํํฐ๋ง์ด ๋จผ์ ์คํ๋จ (WHERE n.regt_id = ?)
- JOIN ํ ๋ฐ๋ก GROUP_CONCAT ์ ์ฉ → ๋ถํ์ํ ์ค๋ณต ์ฐ์ฐ ๊ฐ์
๐น ์์ ๋ ์ฟผ๋ฆฌ
LEFT JOIN note_trans_mgmt ntm2 ON n.note_id = ntm2.note_id AND ntm2.trans_type = '2'
LEFT JOIN users u2 ON ntm2.user_id = u2.user_id
//…WHERE
AND LOWER(u2.user_nm_kr) LIKE CONCAT('%', LOWER(#{keyword}), '%')
๐น ์กฐํ ์๋
- (๋ณด๋ธ ์ชฝ์ง 10๋ง๊ฑด + ๋ค๋ฅธ ์ชฝ์ง x) ์ ์ฒด: 3.06s, ์์ ์ ๊ฒ์: 15.93s
- (๋ณด๋ธ ์ชฝ์ง 20๋ง๊ฑด + ๋ค๋ฅธ ์ชฝ์ง 10๋ง๊ฑด) ์ ์ฒด: 9.76s, ์์ ์ ๊ฒ์: 25.93s
์๋ถํฐ ์ ์ฒด ์กฐํ, ์ ์ฒด ๊ฒ์, ์ ๋ชฉ ๊ฒ์, ๋ด์ฉ ๊ฒ์, ๋ฐ๋ ์ฌ๋ ๊ฒ์
๐น ๋ฌธ์ ์
- ์๋ธ์ฟผ๋ฆฌ๋ฅผ ์ ๊ฑฐํ๋ฉด์ ์กฐํ ์ฑ๋ฅ์ด ํฌ๊ฒ ํฅ์๋จ
- ํ์ง๋ง ์ฌ์ ํ ๋ฐ๋ ์ฌ๋(recv) ๊ฒ์์ LIKE๋ก ์ธํด Full Table Scan ๋ฐ์ ๊ฐ๋ฅ, ๋ฐ์ดํฐ ๋์ด๋๋ฉด ์กฐํ ์๋ ๋ฐฐ๋ก ์ฆ๊ฐ
โญ ์ ์ฒด ๊ฒ์์ด ๋ฐ๋ ์ฌ๋ ๊ฒ์๋ณด๋ค ๋น ๋ฅด๋ค?
โก๏ธ OR ์กฐ๊ฑด ๋๋ฌธ!!
- ์ ๋ชฉ(title)์ด๋ ๋ด์ฉ(content)์์ ๊ฒ์์ด๋ฅผ ์ฐพ์ผ๋ฉด, ๋ค์ ์คํํ์ง ์๊ณ TRUE๊ฐ ๋์ด ๊ฒฐ๊ณผ์ ํฌํจ๋จ
- ์ตํฐ๋ง์ด์ ๊ฐ ์๋์ผ๋ก ์์ ์ต์ ํ ํด์ค๋ค๊ณ ํ๋๋ฐ, ํน์ ๋ชฐ๋ผ์ ์ค๋๊ฑธ๋ฆฌ๋ u2.user_nm_kr์กฐ๊ฑด์ ๋ค์ชฝ์ ๋ฐฐ์นํ๋ค.
โ 3. EXISTS ์ฌ์ฉ (u2 ์กฐ์ธ์ ๊ฑฐ)
๐น๊ฐ์
- ๊ธฐ์กด JOIN์์ LIKE๋ฅผ ์ฌ์ฉํ๋ฉด JOIN ์ดํ ์ ์ฒด ๋ฐ์ดํฐ์์ ๋ฌธ์์ด ๊ฒ์์ ์ํํด์ผ ํ๋ฏ๋ก ๋นํจ์จ์
- EXISTS๋ฅผ ์ฌ์ฉํ๋ฉด ํ์ํ ๋ ์ฝ๋๊ฐ ์กด์ฌํ๋์ง๋ง ํ์ธํ์ฌ ๋ถํ์ํ ๋ฐ์ดํฐ ์กฐํ ๋ฐฉ์ง
- JOIN์ ์ฌ์ฉํ๋ฉด ์ ์ฒด u2.user_nm_kr ํ ์ด๋ธ์ ์ค์บํ ํ LIKE๋ฅผ ์ ์ฉํด์ผ ํ์ง๋ง, EXISTS๋ ๋งค์นญ๋๋ ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด ๋ฐ๋ก ์ข ๋ฃ๋๋ฏ๋ก ๋ถํ์ํ ๋ฐ์ดํฐ ์ค์บ์ ์ค์ผ ์ ์์.
๐น ์์ ๋ ์ฟผ๋ฆฌ
AND EXISTS (
SELECT 1 FROM users u_sub
WHERE u_sub.user_id = ntm2.user_id
AND u_sub.user_nm_kr LIKE CONCAT('%', #{keyword}, '%')
)
๐น ์กฐํ ์๋
(๋ณด๋ธ ์ชฝ์ง 20๋ง๊ฑด + ๋ค๋ฅธ ์ชฝ์ง 10๋ง๊ฑด) ์ ์ฒด: 3.03s, ์์ ์ ๊ฒ์: 13.47s
โ 4. ์ต์ข : Where์กฐ๊ฑด ์์น ์์ , lowerํจ์ ์ ๊ฑฐ, ๋ถํ์ ์ปฌ๋ผ ์ ๊ฑฐ(userNm)
๐น ๊ฐ์
- WHERE ์กฐ๊ฑด์ Join-on์ผ๋ก ์ฎ๊น → ํํฐ๋ง์ ๋จผ์ ์ํํ๊ณ , ์ดํ ์ฐ์ฐ์ ์งํ
- LOWER() ํจ์ ์ ๊ฑฐ → ๋ถํ์ ์ฐ์ฐ ์ ๊ฑฐ(ํ๊ตญ์ด๋ง ๋ค์ด๊ฐ๋ ์ปฌ๋ผ์ด๋ค!!)
- ๋ถํ์ํ ์ปฌ๋ผ(userNm - ๋ณด๋ธ์ฌ๋์ด๋ฆ) ์ ๊ฑฐ → ์ฟผ๋ฆฌ ์ฒ๋ฆฌ๋ ๊ฐ์
๐น์์ ๋ ์ฟผ๋ฆฌ
LEFT JOIN note_trans_mgmt ntm ON n.note_id = ntm.note_id AND ntm.trans_type = "1" AND ntm.use_yn = "Y"
๐น ์กฐํ ์๋
(20๋ง๊ฑด+๋ค๋ฅธ ์ ์ 10๋ง๊ฑด ๊ธฐ์ค) ์ ์ฒด ์กฐํ: 3.17s, ๋ณด๋ธ ์ฌ๋ ๊ฒ์: 11.09s
โญ ์ฐธ๊ณ : ๋ฏธ์ ์ฉ๋ ๋ฐฉ๋ฒ
โ ์ธ๋ฑ์ค ์ถ๊ฐ
์ธ๋ฑ์ค๋ user_nm_kr์ ์ถ๊ฐํ๊ณ %text% -> text%๋ก ๋ฐ๊ฟ ๋ณด์์ง๋ง ์ฌ์ฉ๋์งx, force index ์ฌ์ฉ์ ์คํ๋ ค ์ฑ๋ฅ ๊ฐ์. → ์ธ๋ฑ์ค๋ฅผ ๊ฐ์ ํ ๊ฒฝ์ฐ ๋ฒ์ ๊ฒ์(range scan)์ด ๋ฐ์ํ๋ฉด์ ๋ถํ์ํ ๊ฒ์์ด ์ฆ๊ฐํ ์ ์์
like ๊ฒ์ ํธ์์ฑ์ ์ํด ์ ์ธํจ.
๊ธฐ์กด
1 SIMPLE u2 ref PRIMARY,idx_user_name PRIMARY 162 skku.ntm2.user_id 1 Using where
LEFT JOIN users u2 FORCE INDEX (idx_user_name)ON ntm2.user_id = u2.user_id ์ ์ฉ ์
1 SIMPLE u2 range idx_user_name idx_user_name 323 1463 Using where; Using index; Using join buffer (flat, BNL join)
โ VARCHAR → CHAR
ํ๊ตญ ์ฌ๋ ์ด๋ฆ ๊ธ์ ์ ์ ํ ์ ์ฑ ์์ด์ ๋ฐ์ํ์ง ์์.
ํน์ง CHAR(n) VARCHAR(n)
| ๊ธธ์ด | ๊ณ ์ ๊ธธ์ด (n ๋ฐ์ดํธ) | ๊ฐ๋ณ ๊ธธ์ด (๋ฐ์ดํฐ ๊ธธ์ด + 1~2๋ฐ์ดํธ) |
| ๊ณต๋ฐฑ ์ฒ๋ฆฌ | ์งง์ผ๋ฉด ๊ณต๋ฐฑ( )์ผ๋ก ํจ๋ฉ๋จ | ์ ์ฅ ์ ๊ณต๋ฐฑ ์ ๊ฑฐ๋จ |
| ์๋ | ๊ณ ์ ๊ธธ์ด๋ผ ์ ๋ ฌ ๋ฐ ๊ฒ์์ด ๋น ๋ฅผ ์ ์์ | ๊ธธ์ด ํ์ธ ๊ณผ์ ์ด ์์ด ์ฝ๊ฐ์ ์ค๋ฒํค๋ ๋ฐ์ ๊ฐ๋ฅ |
| ๊ณต๊ฐ ํจ์จ์ฑ | ๊ธธ์ด๊ฐ ์งง์์๋ก ๊ณต๊ฐ ๋ญ๋น ๋ฐ์ ๊ฐ๋ฅ | ํ์ํ ๋งํผ๋ง ์ ์ฅํ์ฌ ๊ณต๊ฐ ํจ์จ์ |
| ์ ํฉํ ๊ฒฝ์ฐ | ๊ธธ์ด๊ฐ ์ผ์ ํ ๋ฐ์ดํฐ (์: ๊ตญ๊ฐ ์ฝ๋, ์ฑ๋ณ ๋ฑ) | ๊ธธ์ด๊ฐ ๋ค์ํ ๋ฌธ์์ด ์ ์ฅ ์ ์ ๋ฆฌ |
โ FULLTEXT,GRAM TABLE
FULLTEXT,GRAM TABLE ๋ฑ์ ํ ๊ธ์, %text% ๊ฒ์์ด ํ์ํด์ ๋ฐ์x.
โ @Transactional(readOnly = true)
์๋ ์ธก์ ์์ ์ฐจ์ดx.
// ๋ณด๋ธ ์ชฝ์ง ๋ชฉ๋ก ์ ์ฒด ์นด์ดํธ
@Transactional(readOnly = true)
public int getSendNotesTotalCnt(Criteria cri) {
return noteMapper.selectNoteByRegtIdTotalCnt(cri);
}
// ๋ณด๋ธ ์ชฝ์ง ๋ชฉ๋ก ๋ฆฌ์คํธ (ํ์ด์ง)
@Transactional(readOnly = true)
public List<NoteResponseDTO> getSendNotes(Criteria cri) {
return noteMapper.selectNoteListByRegtId(cri);
}
โ ๋น๋๊ธฐ ์ฒ๋ฆฌ
์ค์๊ฐ ์ต์ ์ฑ์ด ์ค์ํ ์๋น์ค ํน์ฑ์ ๊ณ ๋ คํด ์ ์ธ.
๐ ๊ฒฐ๋ก
๐น์ต์ข ์ฟผ๋ฆฌ
โ ์๋ธ์ฟผ๋ฆฌ ์ ๊ฑฐ → JOIN์ ์ด์ฉ
โ EXISTS ์ฌ์ฉ → ๋ฌด์กฐ๊ฑด ๋ ๋น ๋ฅด์ง x, ์ฟผ๋ฆฌ ์๋๋ฅผ ๋น๊ตํด๋ณด๊ณ ์ ์ฉํ ๊ฒ!!
โ ๋ถํ์ ํจ์, ์ปฌ๋ผ ์ ๊ฑฐ
<!-- ๋ณด๋ธ ์ชฝ์ง ๊ฐ์ -->
<select id="selectNoteByRegtIdTotalCnt">
SELECT COUNT(DISTINCT n.note_id)
FROM notes n
LEFT JOIN note_trans_mgmt ntm ON n.note_id = ntm.note_id AND ntm.trans_type = "1" AND ntm.use_yn = "Y"
LEFT JOIN note_trans_mgmt ntm2 ON n.note_id = ntm2.note_id AND ntm2.trans_type = '2'
WHERE n.regt_id = #{regtId}
<if test="keyword != null and keyword != ''">
<choose>
<when test="searchOption == 'recv'">
AND EXISTS (
SELECT 1 FROM users u_sub
WHERE u_sub.user_id = ntm2.user_id
AND u_sub.user_nm_kr LIKE CONCAT('%', #{keyword}, '%')
)
</when>
<when test="searchOption == 'titl'">
AND LOWER(n.title) LIKE CONCAT('%', #{keyword}, '%')
</when>
<when test="searchOption == 'cont'">
AND LOWER(n.content) LIKE CONCAT('%', LOWER(#{keyword}), '%')
</when>
<otherwise>
AND (
LOWER(n.title) LIKE CONCAT('%', LOWER(#{keyword}), '%')
OR LOWER(n.content) LIKE CONCAT('%', LOWER(#{keyword}), '%')
OR EXISTS (
SELECT 1 FROM users u_sub
WHERE u_sub.user_id = ntm2.user_id
AND u_sub.user_nm_kr LIKE CONCAT('%', #{keyword}, '%')
)
)
</otherwise>
</choose>
</if>
</select>
<!-- ๋ณด๋ธ ์ชฝ์ง -->
<select id="selectNoteListByRegtId">
SELECT
n.note_id, n.title, n.content, n.regt_id, n.regt_dt
, ntm.trans_id, ntm.trans_type, ntm.read_yn, COUNT(nam.attach_id) as attach_cnt
, GROUP_CONCAT(DISTINCT u2.user_nm_kr) AS recv_nms
FROM notes n
LEFT JOIN note_trans_mgmt ntm ON n.note_id = ntm.note_id AND ntm.trans_type = "1" AND ntm.use_yn = "Y"
LEFT JOIN note_attach_mgmt nam ON n.note_id = nam.attach_id
LEFT JOIN note_trans_mgmt ntm2 ON n.note_id = ntm2.note_id AND ntm2.trans_type = '2'
LEFT JOIN users u2 ON ntm2.user_id = u2.user_id
WHERE n.regt_id = #{regtId}
<if test="keyword != null and keyword != ''">
<choose>
<when test="searchOption == 'recv'">
AND EXISTS (
SELECT 1 FROM users u_sub
WHERE u_sub.user_id = ntm2.user_id
AND u_sub.user_nm_kr LIKE CONCAT('%', #{keyword}, '%')
)
</when>
<when test="searchOption == 'titl'">
AND LOWER(n.title) LIKE CONCAT('%', LOWER(#{keyword}), '%')
</when>
<when test="searchOption == 'cont'">
AND LOWER(n.content) LIKE CONCAT('%', LOWER(#{keyword}), '%')
</when>
<otherwise>
AND (
LOWER(n.title) LIKE CONCAT('%', LOWER(#{keyword}), '%')
OR LOWER(n.content) LIKE CONCAT('%', LOWER(#{keyword}), '%')
OR EXISTS (
SELECT 1 FROM users u_sub
WHERE u_sub.user_id = ntm2.user_id
AND u_sub.user_nm_kr LIKE CONCAT('%', #{keyword}, '%')
)
)
</otherwise>
</choose>
</if>
GROUP BY n.note_id
ORDER BY n.note_id DESC
LIMIT #{pageSize} OFFSET #{startIndex}
</select>
๐ ํ์ด์ง ์๋ ๊ฐ์
๐น ๋ฌธ์ ์
์ฒซ ํ์ด์ง ์กฐํ ์๋๋ ๋ฌธ์ ๊ฐ ์์์ง๋ง, ๋ท ํ์ด์ง๋ก ์ด๋ ์ ์ค๋ ๊ฑธ๋ฆผ
โ LIMIT๊ณผ OFFSET ์๋ ๋ฐฉ์
LIMIT #{pageSize} OFFSET #{startIndex}
โ LIMIT : ๊ฐ์ ธ์ฌ ํ(row)์ ๊ฐ์๋ฅผ ์ง์
โ OFFSET : ๊ฑด๋๋ธ ํ(row)์ ๊ฐ์๋ฅผ ์ง์
๐ฅ ์ ๋๋ ค์ง๊น?
1๏ธโฃ DB๋ OFFSET๋งํผ์ ๋ฐ์ดํฐ๋ฅผ ๋จผ์ ์ฝ๊ณ ๋ฒ๋ ค์ผ ํจ
2๏ธโฃ OFFSET์ด ํด์๋ก ๋ฒ๋ฆฌ๋ ๋ฐ์ดํฐ๊ฐ ๋ง์์ง๊ณ , ๋์คํฌ I/O ์ฆ๊ฐ
์ฆ, OFFSET์ ์์ ๋ฐ์ดํฐ๋ฅผ ๋ค ์ฝ๊ณ ๊ฑด๋๋ด ํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ฏ๋ก ์ฟผ๋ฆฌ ์ฑ๋ฅ์ด ์ ํ๋๋ค. ๐ข
๐น ๊ฐ์
- OFFSET์ ์ ๊ฑฐ
โ ID ๊ธฐ๋ฐ ํ์ด์ง
SELECT * FROM ํ
์ด๋ธ
WHERE note_id < #{๋ง์ง๋ง_note_id}
ORDER BY note_id DESC
LIMIT 10;
โ ์ด์ ํ์ด์ง์ ๋ง์ง๋ง ID(note_id)๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ค์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ๋๋ฌธ์ ์๋๊ฐ ๋น ๋ฆ!
โ INDEX๋ฅผ ํ์ฉํ๋ฏ๋ก OFFSET๋ณด๋ค ํจ์ฌ ํจ์จ์ !
โญ ์ฐธ๊ณ : ๋ฏธ์ ์ฉ ๋ฐฉ๋ฒ
โ ์๋ธ์ฟผ๋ฆฌ๋ก OFFSET ์ต์ ํ
SELECT * FROM ํ
์ด๋ธ
WHERE note_id IN (
SELECT note_id FROM ํ
์ด๋ธ ORDER BY note_id DESC LIMIT 10 OFFSET 1000
);
โ OFFSET์ด ํฐ ๊ฒฝ์ฐ, ๋จผ์ ID๋ง ์ฐพ๊ณ ์ต์ ํํ ์ ์์
โ ํ์ด์ง์ ์บ์ฑํ๊ธฐ
โ ๊ฐ์ ์ฟผ๋ฆฌ๊ฐ ๋ฐ๋ณต๋๋ฉด Redis ๊ฐ์ ์บ์ ํ์ฉ
๐ ๊ฒฐ๋ก
โ OFFSET๋์ ๋ง์ง๋ง ์กฐํ ๋ฐ์ดํฐ ID๋ฅผ ๊ธฐ์ค์ผ๋ก ์กฐํ
โ ํ๋ก ํธ์๋์์ ์์์ ๋ฐ์ดํฐ ID๋ฅผ ๊ฐ์ง๊ณ ์๋ค๊ฐ ๋ณด๋ด์ฃผ๋ ์ฒ๋ฆฌ ํ์ํจ!!
๐น ์กฐํ ์๋
์ฒซ ํ์ด์ง ์กฐํ ์๋, ๋ง์ง๋ง ํ์ด์ง ์กฐํ ์๋
๐น์ต์ข ์ฟผ๋ฆฌ
<select id="selectNoteListByRegtId">
SELECT
n.note_id, n.title, n.content, n.regt_id, n.regt_dt
, ntm.trans_id, ntm.trans_type, ntm.read_yn, COUNT(nam.attach_id) as attach_cnt
, GROUP_CONCAT(DISTINCT u2.user_nm_kr) AS recv_nms
FROM notes n
LEFT JOIN note_trans_mgmt ntm ON n.note_id = ntm.note_id AND ntm.trans_type = "1" AND ntm.use_yn = "Y"
LEFT JOIN note_attach_mgmt nam ON n.note_id = nam.attach_id
LEFT JOIN note_trans_mgmt ntm2 ON n.note_id = ntm2.note_id AND ntm2.trans_type = '2'
LEFT JOIN users u2 ON ntm2.user_id = u2.user_id
WHERE n.regt_id = #{regtId}
<if test="lastSno != 0">
AND n.note_id <![CDATA[<]]> #{lastSno}
</if>
<if test="keyword != null and keyword != ''">
<choose>
<when test="searchOption == 'recv'">
AND EXISTS (
SELECT 1 FROM users u_sub
WHERE u_sub.user_id = ntm2.user_id
AND u_sub.user_nm_kr LIKE CONCAT('%', #{keyword}, '%')
)
</when>
<when test="searchOption == 'titl'">
AND LOWER(n.title) LIKE CONCAT('%', LOWER(#{keyword}), '%')
</when>
<when test="searchOption == 'cont'">
AND LOWER(n.content) LIKE CONCAT('%', LOWER(#{keyword}), '%')
</when>
<otherwise>
AND (
LOWER(n.title) LIKE CONCAT('%', LOWER(#{keyword}), '%')
OR LOWER(n.content) LIKE CONCAT('%', LOWER(#{keyword}), '%')
OR EXISTS (
SELECT 1 FROM users u_sub
WHERE u_sub.user_id = ntm2.user_id
AND u_sub.user_nm_kr LIKE CONCAT('%', #{keyword}, '%')
)
)
</otherwise>
</choose>
</if>
GROUP BY n.note_id
ORDER BY n.note_id DESC
LIMIT #{pageSize}
</select>
- ์๋ ๋น๊ต
# offset ์ด์ฉ - 5.694s
SELECT
n.note_id, n.title, n.content, n.regt_id, n.regt_dt
, ntm.trans_id, ntm.trans_type, ntm.read_yn, COUNT(nam.attach_id) as attach_cnt
, GROUP_CONCAT(DISTINCT u2.user_nm_kr) AS recv_nms
FROM notes n
LEFT JOIN note_trans_mgmt ntm ON n.note_id = ntm.note_id AND ntm.trans_type = "1" AND ntm.use_yn = "Y"
LEFT JOIN note_attach_mgmt nam ON n.note_id = nam.attach_id
LEFT JOIN note_trans_mgmt ntm2 ON n.note_id = ntm2.note_id AND ntm2.trans_type = '2'
LEFT JOIN users u2 ON ntm2.user_id = u2.user_id
WHERE n.regt_id = 'user1'
GROUP BY n.note_id
ORDER BY n.note_id desc
limit 10 offset 100000
# ID๊ธฐ๋ฐ ์กฐํ - 0.479s
SELECT
n.note_id, n.title, n.content, n.regt_id, n.regt_dt
, ntm.trans_id, ntm.trans_type, ntm.read_yn, COUNT(nam.attach_id) as attach_cnt
, GROUP_CONCAT(DISTINCT u2.user_nm_kr) AS recv_nms
FROM notes n
LEFT JOIN note_trans_mgmt ntm ON n.note_id = ntm.note_id AND ntm.trans_type = "1" AND ntm.use_yn = "Y"
LEFT JOIN note_attach_mgmt nam ON n.note_id = nam.attach_id
LEFT JOIN note_trans_mgmt ntm2 ON n.note_id = ntm2.note_id AND ntm2.trans_type = '2'
LEFT JOIN users u2 ON ntm2.user_id = u2.user_id
WHERE n.regt_id = 'user1' and n.note_id < '291276'
GROUP BY n.note_id
ORDER BY n.note_id desc
limit 10
'DB > RDBMS' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [MySQL] ๋ฌธ์ ์ธ์ฝ๋ฉ ๋ณ๊ฒฝ (์๋ฌ ์ฒ๋ฆฌ) (0) | 2025.11.08 |
|---|---|
| [MariaDB] ์ธ๋ํค ์์ฑ/์ญ์ ๋ฐฉ๋ฒ (0) | 2024.11.30 |
| ์ฟผ๋ฆฌ ์คํ ์๋ ํ์ธ (0) | 2024.05.30 |
| ์๋ธ ์ฟผ๋ฆฌ ORDER BY (0) | 2023.10.23 |
| [MariaDB] RECURSIVE ๊ณ์ธต ๋ฉ๋ด ๊ตฌ์ฑ (0) | 2023.08.14 |