๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

pagination

[Anifriends] ํŽ˜์ด์ง€๋„ค์ด์…˜ ์„ฑ๋Šฅ๊ฐœ์„ 

๐Ÿš€ ๊ฐœ์š”

๋ฐ๋ธŒ์ฝ”์Šค 4๊ธฐ์—์„œ ๋™๋ฌผ ๋ณดํ˜ธ์†Œ์™€ ๋ด‰์‚ฌ์ž ๋งค์นญ ํ”Œ๋žซํผ์ธ AniFriends ๋ฅผ ๊ฐœ๋ฐœํ•˜๋ฉด์„œ ๊ฒฝํ—˜ํ•œ ํŽ˜์ด์ง€๋„ค์ด์…˜ ์„ฑ๋Šฅ ๊ฐœ์„ ๊ธฐ์ด๋‹ค. ๋ด‰์‚ฌ์ž๋Š” ๋ด‰์‚ฌ ๋ชจ์ง‘ ๋ชฉ๋ก์„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์„œ๋ฒ„์—์„œ๋Š” ๋ชจ์ง‘ ๋ชฉ๋ก์„ ํŽ˜์ด์ง€๋„ค์ด์…˜์œผ๋กœ ์‘๋‹ตํ•œ๋‹ค. 100๋งŒ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜์—ฌ ์กฐํšŒ ์„ฑ๋Šฅ์„ ์ธก์ •ํ•˜์˜€๋‹ค.

๐Ÿšจ ๊ฐœ์„  ์ „

offset ์ด ๊ฐ๊ฐ 0/500,000/900,000์ผ ๋•Œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์•ฝ 5~7์ดˆ๊ฐ€ ์†Œ์š”๋œ๋‹ค.

offset: 0 / size: 20
offset: 500,000 / size: 20
offset: 900,000 / size: 20

 

โœ…  ์ธ๋ฑ์Šค

์šฐ์„ , ์ •๋ ฌ ๊ธฐ์ค€์ธ created_at ์— ๋‚ด๋ฆผ์ฐจ์ˆœ ์ธ๋ฑ์Šค๋ฅผ ์ ์šฉํ•ด๋ณด์ž

created_at desc ์ธ๋ฑ์Šค ์ ์šฉ

์ธ๋ฑ์Šค ์ ์šฉ ํ›„์˜ ์†Œ์š”์‹œ๊ฐ„์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

offset: 0 / size: 20
offset: 500,000 / size: 20
offset: 900,000 / size: 20

offset ์ด 0์ผ ๊ฒฝ์šฐ ์†Œ์š”์‹œ๊ฐ„์ด 5.3์ดˆ์—์„œ 0.1์ดˆ๋กœ ์•ฝ 50๋ฐฐ ๊ฐ์†Œ๋˜์—ˆ๋‹ค. ํ•˜์ง€๋งŒ offset ์ด 500,000/900,000์ผ ๊ฒฝ์šฐ๋Š” ์ „ํ˜€ ๊ฐœ์„ ๋˜์ง€ ์•Š์•˜๋‹ค. ์ด์œ ๊ฐ€ ๋ฌด์—‡์ผ๊นŒ? ์‹คํ–‰๊ณ„ํš์„ ํ™•์ธํ•ด๋ณด์ž

offset: 0 / size: 20
offset: 500,000 / size: 20
offset: 900,000 / size: 20
  • type ์„ ๋ณด๋ฉด offset ์ด 0์ผ ๋•Œ๋Š” index ์ด๊ณ  500,000/900,000์ผ ๋•Œ๋Š” ALL์ด๋‹ค.
  • rows ๋ฅผ ๋ณด๋ฉด offset ์ด 0์ผ ๋•Œ๋Š” 20์ด๊ณ  500,000/900,000์ผ ๋•Œ๋Š” ์•ฝ 1,000,000์ด๋‹ค.
  • Extra ๋ฅผ ๋ณด๋ฉด 500,000/900,000์ผ ๋•Œ Using filesort(์ถ”๊ฐ€์ ์ธ ์ •๋ ฌ ์ž‘์—…์„ ์˜๋ฏธ) ๊ฐ€ ์กด์žฌํ•œ๋‹ค.

์ด๋ฅผ ํ†ตํ•ด offset ์ด ์–ด๋Š์ •๋„ ์ปค์ง€๋ฉด index ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  table full scan ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. Mysql ๊ณต์‹๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด, ์ฟผ๋ฆฌ์—์„œ ๋Œ€๋ถ€๋ถ„์˜ ํ–‰์— ์•ก์„ธ์Šคํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์ธ๋ฑ์Šค๋ฅผ ํ†ตํ•ด ์ž‘์—…ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์ˆœ์ฐจ์ ์œผ๋กœ ์ฝ๋Š” ๊ฒƒ์ด ๋” ๋น ๋ฅด๋‹ค๊ณ  ํŒ๋‹จํ•œ๋‹ค๊ณ  ํ•œ๋‹ค. ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์ปค๋ฒ„๋ง ์ธ๋ฑ์Šค์™€ ์ปค์„œ ๋ฐฉ์‹์„ ์ ์šฉํ•ด๋ณด๋„๋ก ํ•˜์ž

โœ…  ์ปค๋ฒ„๋ง ์ธ๋ฑ์Šค

์ปค๋ฒ„๋ง ์ธ๋ฑ์Šค๋ž€ ์ฟผ๋ฆฌ์˜ ๋ชจ๋“  ํ•ญ๋ชฉ์ด ์ธ๋ฑ์Šค ์ปฌ๋Ÿผ์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ์ปค๋ฒ„๋ง ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์‹ค์ œ ๋ฐ์ดํ„ฐ ๋ธ”๋ก์— ์ ‘๊ทผํ•  ํ•„์š” ์—†์ด ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋‹ค. ์ปค๋ฒ„๋ง ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•œ ์ฟผ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

select * from recruitment r
	join (select recruitment_id from recruitment
    		order by created_at desc
            	limit [offset], [size]) temp on r.recruitment_id = temp.recruitment_id
    	join shelter s r.shelter_id = s.shelter_id;

์ฒซ ๋ฒˆ์งธ join ์˜  ์„œ๋ธŒ์ฟผ๋ฆฌ๋ฅผ ์‚ดํŽด๋ณด๋ฉด select ์ปฌ๋Ÿผ์€ pk ์ธ recruitment_id ์ด๊ณ  order by ์ปฌ๋Ÿผ์€ ์ธ๋ฑ์Šค๋ฅผ ์ ์šฉํ•œ created_at ์ด๋‹ค. ์ฆ‰, ์ฟผ๋ฆฌ์˜ ๋ชจ๋“  ํ•ญ๋ชฉ์ด ์ธ๋ฑ์Šค ์ปฌ๋Ÿผ์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋‹ค. ์ด์ œ ์†Œ์š” ์‹œ๊ฐ„์„ ํ™•์ธํ•ด๋ณด์ž.

offset: 0 / size: 20
offset: 500,000 / size: 20
offset: 900,000 / size: 20

์ปค๋ฒ„๋ง ์ธ๋ฑ์Šค๋ฅผ ์ ์šฉํ•œ ๊ฒฐ๊ณผ offset ์ด 500,000/900,000 ์ธ ๊ฒฝ์šฐ๋„ ์•ฝ 40๋ฐฐ๊ฐ€ ๊ฐ์†Œ๋œ 0.2~0.3์ดˆ๊ฐ€ ์†Œ์š”๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์ปค๋ฒ„๋ง ์ธ๋ฑ์Šค๋ฅผ ์ ์šฉํ•œ ํ›„์˜ ์‹คํ–‰๊ณ„ํš์€ ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? offset ์ด 900,000 ์ผ ๊ฒฝ์šฐ๋ฅผ ํ™•์ธํ•ด๋ณด์ž.

offset ์ด 900,000 ์ผ ๊ฒฝ์šฐ์˜ ์‹คํ–‰ ๊ณ„ํš

select_type ์ด DERIVED(from ์ ˆ์˜ ์„œ๋ธŒ์ฟผ๋ฆฌ) ์ธ ํ–‰์˜ Extra ๋ฅผ ๋ณด๋ฉด Using index ์ด๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ๋ถ€๋ถ„์— ์ปค๋ฒ„๋ง ์ธ๋ฑ์Šค๊ฐ€ ์ ์šฉ๋œ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

โœ…  ์ปค์„œ ๋ฐฉ์‹

์ปค์„œ๋ฐฉ์‹์ด๋ž€ offset ์„ 0 ์œผ๋กœ ์„ค์ •ํ•˜๊ณ  ํŠน์ • ์ง€์ (์ปค์„œ)์„ where ๋ฌธ์œผ๋กœ ์„ค์ •ํ•˜์—ฌ ๊ทธ ์ง€์ ๋ถ€ํ„ฐ ํŠน์ • ๊ฐœ์ˆ˜๋งŒํผ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ์‹์ด๋‹ค. offset ์ด 0์ด๊ธฐ ๋•Œ๋ฌธ์— ํ•ญ์ƒ ์ฒซ ํŽ˜์ด์ง€๋ฅผ ์กฐํšŒํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•œ ์„ฑ๋Šฅ์„ ๋‚ผ ์ˆ˜ ์žˆ๋‹ค. ๋ด‰์‚ฌ ๋ชจ์ง‘๊ธ€์˜ ์ •๋ ฌ ๊ธฐ์ค€์€ created_at ๊ธฐ์ค€ ๋‚ด๋ฆผ์ฐจ์ˆœ์ด๊ณ  created_at ๋งˆ์ € ๊ฐ™์„ ๊ฒฝ์šฐ recruitment_id ๊ธฐ์ค€ ๋‚ด๋ฆผ์ฐจ์ˆœ์ด๋‹ค. ์ปค์„œ๋ฐฉ์‹์„ ์ ์šฉํ•œ ์ฟผ๋ฆฌ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค. 

select * from recruitment r
    join shelter s on s.shelter_id=r.shelter_id
    where r.created_at < [created_at ์ปค์„œ]
        or (r.created_at = [created_at ์ปค์„œ] and r.recruitment_id < [recruitment_id ์ปค์„œ])
    order by r.created_at desc
    limit [size];

์ด์ œ offset ์ด 900,000 ์ธ ์ปค์„œ๋ฅผ ์„ ํƒํ•ด์„œ ์†Œ์š”์‹œ๊ฐ„์„ ์ธก์ •ํ•ด๋ณด์ž. limit 899999, 1 ์„ ํ†ตํ•ด 900,000 ๋ฒˆ์งธ์˜ ์ปค์„œ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

899,999 ๋ฒˆ์งธ ๋ฐ์ดํ„ฐ

์‹คํ–‰ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

offset: 0 / size: 20

์ปค๋ฒ„๋ง ์ธ๋ฑ์Šค๋ณด๋‹ค 50๋ฐฐ๊ฐ€ ๊ฐ์†Œ๋œ 0.1 ์ดˆ๊ฐ€ ์†Œ์š”๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

์• ๋‹ˆํ”„๋ Œ์ฆˆ์˜ ๋ด‰์‚ฌ ๋ชจ์ง‘ ๋ชฉ๋ก ์กฐํšŒ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ๋ฌดํ•œ ์Šคํฌ๋กค ๋ฐฉ์‹์ด๋ฉฐ offset ์„ ํ•„์š”๋กœ ํ•˜์ง€์•Š๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ์ด ์กฐ๊ธˆ ๋” ๋‚˜์€ ์ปค์„œ๋ฐฉ์‹์„ ์„ ํƒํ•˜์˜€๋‹ค.