Skip to content

Query Optimization (1)

gintooooonic edited this page Nov 8, 2021 · 1 revision

์ฟผ๋ฆฌ ์ตœ์ ํ™”

DB ์‹œ์Šคํ…œ์ด๋‚˜ ์ธ๋ฑ์Šค, ์ฟผ๋ฆฌ ๋“ฑ ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ์ฃผ๋Š” ์š”์†Œ๋“ค์ด ๋งŽ์„ ๊ฒƒ์œผ๋กœ ์ƒ๊ฐ๋จ. DB ์‹œ์Šคํ…œ ํŠœ๋‹์„ ํ†ตํ•ด ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•˜๋Š” ๊ฒƒ์€ DBA์˜ ์—…๋ฌด๊ฒ ์ง€๋งŒ, ์„ฑ๋Šฅ์„ ์ €ํ•˜์‹œํ‚ค์ง€ ์•Š๋Š” ์ข‹์€ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ๊ฐœ๋ฐœ์ž์˜ ์—…๋ฌด์ธ ๊ฒƒ ๊ฐ™๋‹ค.

WATCHA ๊ธฐ์ˆ  ๋ธ”๋กœ๊ทธ: ์ฟผ๋ฆฌ ์ตœ์ ํ™”: ๋น ๋ฅธ ์ฟผ๋ฆฌ๋ฅผ ์œ„ํ•œ 7๊ฐ€์ง€ ์ฒดํฌ๋ฆฌ์ŠคํŠธ โœ…

  1. SELECT์‹œ ํ•„์š”ํ•œ ์ตœ์†Œํ•œ์˜ ์ปฌ๋Ÿผ๋งŒ์„ ๊ฐ€์ ธ์˜ค๊ธฐ
    ๊ฒŒ์‹œ๊ธ€ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์š”์ฒญ์—์„œ post.content ๋“ฑ ๋ถˆํ•„์š”ํ•œ ์ปฌ๋Ÿผ์„ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๋Š”๊ฒŒ ์ข‹์Œ. ๋ฆฌ์ŠคํŠธ์—์„œ ์‚ฌ์šฉํ•  ์ปฌ๋Ÿผ๋งŒ์„ ๊ฐ€์ ธ์˜ค๊ธฐ.

  2. ์กฐ๊ฑด ์—ฐ์‚ฐ์‹œ Index ๊ฐ’์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ธฐ์กด ์ปฌ๋Ÿผ ๊ฐ’์— ๋ณ„๋„์˜ ์—ฐ์‚ฐ ๊ฑธ์ง€ ์•Š๊ธฐ
    ์œ„์น˜ ํ•„ํ„ฐ๋ง์„ ์œ„ํ•ด ์œ„๋„, ๊ฒฝ๋„๋ฅผ ์‚ฌ์šฉํ•ด ๊ฑฐ๋ฆฌ ๊ณ„์‚ฐ์„ ํ•˜๊ฒŒ ๋˜๋ฉด ์ปฌ๋Ÿผ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ œ๊ณฑ ๋“ฑ์˜ ๊ณ„์‚ฐ์ด ๋“ค์–ด๊ฐ€๊ฒŒ ๋จ. ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ์ปฌ๋Ÿผ ๊ฐ’์— ์—ฐ์‚ฐ์ด ๋“ค์–ด๊ฐ€์ง€ ์•Š๋„๋ก ๊ณ ๋ฏผํ•ด๋ณด๊ธฐ.

  3. LIKE ์‚ฌ์šฉ์‹œ ๋ฌธ์ž์—ด ์•ž๋ถ€๋ถ„์—๋Š” % ๋„ฃ์ง€ ์•Š๊ธฐ
    ๊ฒ€์ƒ‰์–ด ํ•„ํ„ฐ๋ง์‹œ %๊ฒ€์ƒ‰์–ด%์™€ ๊ฐ™์ด ๊ฒ€์ƒ‰ํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์„๊นŒ?

  4. ์ค‘๋ณต ๊ฐ’ ์ œ๊ฑฐ ์—ฐ์‚ฐ ์‚ฌ์šฉ ์ง€์–‘ํ•˜๊ธฐ (SELECT DISTINCT, UNION DISTINCT ๋“ฑ)
    ์ค‘๋ณต ๊ฐ’ ์ œ๊ฑฐ ์—ฐ์‚ฐ์˜ Cost๊ฐ€ ํผ. ์ค‘๋ณต ์ œ๊ฑฐ ์—ฐ์‚ฐ์ด ํ•„์š”ํ•˜๋‹ค๋ฉด EXISTS ํ™œ์šฉ ๋“ฑ ๋Œ€์ฒด ๋ฐฉ๋ฒ•์„ ๊ณ ๋ฏผํ•ด๋ณผ ๊ฒƒ.

  5. GROUP BY์‹œ WHERE๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด HAVING ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ธฐ
    WHERE๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ ํฌ๊ธฐ๋ฅผ ์ค„์—ฌ๋†“์œผ๋ฉด GROUP BY ์—ฐ์‚ฐ์— ๋„์›€์ด ๋จ.

  6. 3๊ฐœ ์ด์ƒ์˜ ํ…Œ์ด๋ธ” JOIN์‹œ ๊ฐ€์žฅ ํฐ ํ…Œ์ด๋ธ”์„ FROM์— ๋ฐฐ์น˜ํ•˜๊ณ  ๋‚˜๋จธ์ง€๋Š” ํฌ๊ธฐ๊ฐ€ ์ž‘์€ ์ˆœ์œผ๋กœ JOIN
    ์ฟผ๋ฆฌ ํ”Œ๋ž˜๋‹ ์‹œ๊ฐ„์„ ์ค„์—ฌ์ค„ ์ˆ˜ ์žˆ์œผ๋‚˜, ํ•ญ์ƒ ํšจ๊ณผ๊ฐ€ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹˜.

  7. ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ์ดํ„ฐ๋Š” ๋ฏธ๋ฆฌ ์ „์ฒ˜๋ฆฌ๋œ ํ…Œ์ด๋ธ”์— ์ €์žฅํ•ด๋‘๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ
    RDBMS์˜ ์›์น™์—๋Š” ์–ด๊ธ‹๋‚  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ž„.

๊ฒŒ์‹œ๊ธ€ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ฟผ๋ฆฌ ๊ฐœ์„ 

์ƒํ™ฉ

  1. post, category, participant ํ…Œ์ด๋ธ”์ด ํ•„์š”
  2. ์นดํ…Œ๊ณ ๋ฆฌ์˜ ์ด๋ฆ„์„ ๋ฐ˜ํ™˜ํ•ด์•ผํ•จ (category.name)
  3. ๊ฒŒ์‹œ๊ธ€๋งˆ๋‹ค ์ฐธ์—ฌ์ž์˜ ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผํ•จ (participant์—์„œ postId๋กœ ๊ฒ€์ƒ‰์‹œ์˜ count)

๊ธฐ์กด ๋ฐฉ๋ฒ•

์šฐ์„  post์™€ category ํ…Œ์ด๋ธ”๋งŒ์„ ์กฐ์ธํ•ด ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค์Œ, ๋ฆฌ์ŠคํŠธ๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ ๊ฒŒ์‹œ๊ธ€ ๊ฐ๊ฐ participant ํ…Œ์ด๋ธ”์—์„œ ๊ฒ€์ƒ‰ํ•˜๊ณ  ์žˆ์Œ

const posts = await postService.getPosts(req.query as getPostsOption);
const result = await Promise.all(
  posts.map(async (post: any) => {
    const [participant, participantCnt] =
      await participantService.getParticipantNum(post.id);
    post.participantCnt = participantCnt;
    return post;
  })
);

LIMIT์ด 20์ธ๊ฒฝ์šฐ, API ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ๋•Œ๋งˆ๋‹ค DB์—์„œ๋Š” 21๋ฒˆ์˜ I/O๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ์†๋„ ์ €ํ•˜ ์šฐ๋ ค๊ฐ€ ์žˆ์Œ

๊ฐœ์„ ํ•œ ๋ฐฉ๋ฒ•

GROUP BY๋ฅผ ํ™œ์šฉ, ํ•˜๋‚˜์˜ ์ฟผ๋ฆฌ๋ฅผ ํ†ตํ•ด ์ฐธ์—ฌ์ž ์ˆ˜๋ฅผ ํฌํ•จํ•œ ๊ฒŒ์‹œ๊ธ€ ๋ฆฌ์ŠคํŠธ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Œ

select post.id, title, capacity, deadline, c.name as category, count(p.userId) as joined
from post
left join category c
on post.categoryId = c.id
left join participant p
on post.id = p.postId
group by id
limit 20;

์‹คํ–‰ ๊ฒฐ๊ณผ

๊ธฐ์กด ๋ฐฉ๋ฒ• ๊ฐœ์„ ํ•œ ๋ฐฉ๋ฒ•
      
method1: 445.767ms
method1: 133.723ms
method1: 151.245ms
method1: 138.503ms
method1: 152.716ms
      
    
      
method2: 355.008ms
method2: 62.561ms
method2: 69.565ms
method2: 70.726ms
method2: 70.667ms
      
    
ํ‰๊ท  204.3908ms ํ‰๊ท  125.7054ms

๐Ÿ“– ๊ฐœ๋ฐœ๋ฌธ์„œ

๐Ÿšฅ ๊ทœ์น™

๐Ÿค” ์Šคํ”„๋ฆฐํŠธ ํšŒ์˜

๐Ÿ“” ํ•™์Šต

๐Ÿ•™ ๋ฐ์ผ๋ฆฌ ์Šคํฌ๋Ÿผ

๐Ÿ’ญ ํšŒ๊ณ ๋ก

๐Ÿ‘จโ€๐Ÿ‘ฆ ๋ฉ˜ํ† ๋ง

๋ฐ๋ชจ์˜์ƒ

Clone this wiki locally