N+1 Error

StepByStepCS

๋ชฉ๋ก ๋ณด๊ธฐ
3/3
post-thumbnail

๐Ÿ”น N+1 ์ด๋ž€?

  • ์—ฐ๊ด€ ๊ด€๊ณ„์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ด์Šˆ๋กœ ์—ฐ๊ด€ ๊ด€๊ณ„๊ฐ€ ์„ค์ •๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•  ๊ฒฝ์šฐ์— ์กฐํšŒ๋œ ๋ฐ์ดํ„ฐ ๊ฐฏ์ˆ˜(n) ๋งŒํผ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์กฐํšŒ ์ฟผ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€๋กœ ๋ฐœ์ƒํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์˜ค๊ฒŒ ๋œ๋‹ค. ์ด๋ฅผ N+1 ๋ฌธ์ œ๋ผ๊ณ  ํ•œ๋‹ค.
1๋ฒˆ ์ฟผ๋ฆฌ: ๋ถ€๋ชจ ๋ชฉ๋ก ์กฐํšŒ (1๋ฒˆ)
N๋ฒˆ ์ฟผ๋ฆฌ: ๊ฐ ๋ถ€๋ชจ๋งˆ๋‹ค ์ž์‹ ์กฐํšŒ (N๋ฒˆ)
โ†’ ์ด N+1๋ฒˆ ์ฟผ๋ฆฌ ์‹คํ–‰

๐Ÿ“Œ ๋ฌธ์ œ์˜ ๋ณธ์งˆ
์ฟผ๋ฆฌ ๊ฐœ์ˆ˜๊ฐ€ ๊ธฐํ•˜๊ธ‰์ˆ˜์ ์œผ๋กœ ๋Š˜์–ด๋‚จ
์„ฑ๋Šฅ ์ €ํ•˜ (ํŠนํžˆ ๋„คํŠธ์›Œํฌ, DB ๋ถ€ํ•˜)

์™œ ๋ฐœ์ƒ์„ ํ•˜๋ƒ??

ORM์œผ๋กœ ์ง„ํ–‰ ํ•˜๋ฉด์„œ ๊ธฐ๋ณธ ์กฐํšŒ ๋ฐฉ์‹์€ Lazy Loading์ด๊ธฐ ๋•Œ๋ฌธ์— ORM๋‚ด์—์„œ
์—”ํ‹ฐํ‹ฐ ์ •์˜ ๋ฐ FK ๋“ฑ์„ ์ฐธ์กฐํ•ด ์ตœ์ ์˜ ์ฟผ๋ฆฌ๋ฅผ ํ•œ ํŠธ๋ Œ์ ์…˜์— ๋งŒ๋“ ๋‹ค.

์ด๋–„, ๊ธฐ์ค€ ํ…Œ์ด๋ธ” ์กฐํšŒ + ์ž์‹ ํ…Œ์ด๋ธ” ์กฐํšŒ ๋˜๋Š” ํ–‰๋งˆ๋‹ค ๋ชจ๋‘ ์ถ”๊ฐ€๋กœ ์กฐํšŒ ๋œ๋‹ค.

์˜ˆ์ œ

  • ์—”ํ‹ฐํ‹ฐ ์ •์˜

Order ์™€ Customer ๋Š” N:1 ๊ด€๊ณ„์ด๋ฉฐ,
ORM(Entity Framework) ๊ธฐ์ค€์œผ๋กœ Lazy Loading ์ด ๊ธฐ๋ณธ ๋™์ž‘์ด๋ผ๊ณ  ๊ฐ€์ •

public class Order
{
    public int Id { get; set; }
    public int CustomerId { get; set; }

    public Customer Customer { get; set; } // N:1 ๊ด€๊ณ„
}

public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }
}

๋ฌธ์ œ ๋ฐœ์ƒ ์ฝ”๋“œ (N+1 ๋ฐœ์ƒ ์ง€์ )
Order ๊ฐ์ฒด์—์„œ Customer ์— ์ ‘๊ทผํ•˜๋Š” ์ˆœ๊ฐ„,
Order ๊ฐ์ฒด์— Customer.Name ๋ฐ์ดํ„ฐ๊ฐ€ ์—†์Œ์œผ๋กœ ORM์ด ํŒ๋‹จ
๊ฐ Order ๋งˆ๋‹ค Customer ์กฐํšŒ ์ฟผ๋ฆฌ๋ฅผ ์ถ”๊ฐ€๋กœ ์‹คํ–‰

var orders = context.Orders.ToList();   // (1) ์ฃผ๋ฌธ ๋ชฉ๋ก ์กฐํšŒ โ†’ ์ฟผ๋ฆฌ 1๋ฒˆ

foreach (var o in orders)
{
    Console.WriteLine(o.Customer.Name); // (2) ์ฃผ๋ฌธ ์ˆ˜(N)๋งŒํผ ์ฟผ๋ฆฌ ๋ฐœ์ƒ
}

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ "N+1์˜ ์˜ค๋ฅ˜"๋ผ๊ณ  ํ•˜๋ฉฐ ORM์˜ ๊ฐ์ฒด์ฃผ์˜ ์ปจํ…์Šค ๊ธฐ๋ฐ˜ ํŠธ๋ Œ์ ์…˜ ์ž๋™ํ™” ์‹คํ–‰ ์ฆ‰, ์—”ํ‹ฐํ‹ฐ๊ธฐ๋ฐ˜ ์ตœ์ ์˜ ์ฟผ๋ฆฌ๋ฅผ ์ƒ์„ฑ ๋ฐ ์กฐํšŒ ์‹œ ๊ธฐ๋ณธ ์ „๋žต(Lazy Loading) ๋ฌธ์ œ์ด๋‹ค.

ํ•ด๊ฒฐ๋ฒ•์œผ๋กœ๋Š” ์กฐํšŒ ๋ฐฉ์‹์„ Include ๋ฅผ ์„ ์–ธํ•˜๊ฑฐ๋‚˜ ํ˜น์€ ADO ํ˜•์‹์œผ๋กœ ์ž‘์„ฑ์„ ํ•˜๋Š”๊ฒƒ์„ ๊ถŒ์žฅํ•˜๊ณ  ์žˆ๋‹ค.

์ฑ—์ง€ํ”ผํ‹ฐ ํ•œ์ค„ ์š”์•ฝ

N+1 ๋ฌธ์ œ๋Š” ORM์—์„œ ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ Lazy Loading ๋ฐฉ์‹์œผ๋กœ ์กฐํšŒํ•  ๋•Œ,
๋ถ€๋ชจ ์กฐํšŒ 1๋ฒˆ ์ดํ›„ ์ž์‹ ์กฐํšŒ๊ฐ€ N๋ฒˆ ์ถ”๊ฐ€๋กœ ๋ฐœ์ƒํ•˜๋Š” ์„ฑ๋Šฅ ๋ฌธ์ œ์ด๋‹ค.
ORM์€ ๊ฐ์ฒด ์ค‘์‹ฌ ๊ฐœ๋ฐœ๊ณผ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ์— ๊ฐ•์ ์ด ์žˆ์ง€๋งŒ,
์กฐํšŒ ์ „๋žต์„ ์ž˜๋ชป ์‚ฌ์šฉํ•˜๋ฉด N+1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
๋ฐ˜๋ฉด ADO๋Š” ์ฟผ๋ฆฌ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜๋ฏ€๋กœ JOIN์„ ํ†ตํ•œ ๋‹จ์ผ ์กฐํšŒ๊ฐ€ ๋ช…ํ™•ํ•ด
N+1 ๋ฌธ์ œ๊ฐ€ ๊ตฌ์กฐ์ ์œผ๋กœ ์ ๋‹ค.

์ถ”๊ฐ€ ORM , ADO

๐Ÿ”น ORM(Object Relational Mapping) ์ด๋ž€?

  • ORM ์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํ…Œ์ด๋ธ”์„ ์ฝ”๋“œ์—์„œ ๊ฐ์ฒด์ฒ˜๋Ÿผ ํ•ธ๋“ค๋ง ํ•  ์ˆ˜์žˆ๋„๋ก ๋งคํ•‘ํ•ด์ฃผ๋Š” ๊ธฐ์ˆ ์ด๋‹ค.
    ์ฆ‰, ๊ฐœ๋ฐœ์ž๊ฐ€ SQL ๋ฌธ์„ ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„ ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฃจ๋“ฏ์ด DB ๋ฅผ ํ•ธ๋“ค๋งํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.

ORM ์˜ ๊ธฐ๋ณธ ์‚ฌ๊ณ ๋ฐฉ์‹

  • ORM ์—์„œ๋Š” DB ๊ฐ€ ์ฃผ์ฒด๋ผ๊ธฐ๋ณด๋‹ค๋Š” ๊ฐ์ฒด๊ฐ€ ์ฃผ์ฒด๊ฐ€ ๋œ๋‹ค.

๊ฐœ๋ฐœ์ž ์ž…์žฅ์—์„  ๊ฐ์ฒด ์ ‘๊ทผ
DB ์ž…์žฅ์—์„  ํ•˜๋‚˜์˜ ์ฟผ๋ฆฌ

order.Customer.Name
  • ์œ„์— ์ฝ”๋“œ๋ฐ•์Šค์˜ ORM์€ Context ๋‚ด์— ๋ˆ„์ ๋˜์–ด ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜ ๋‹จ์œ„๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.
  • Context ์•ˆ์—์„œ ์–ด๋–ค ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋๋Š”์ง€, ์–ด๋–ค ๊ด€๊ณ„(FK)๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”์ง€ ์–ด๋–ค ์ˆœ์„œ๋กœ Insert / Update / Delete ํ•ด์•ผ ํ•˜๋Š”์ง€ ORM ์ด ๋‚ด๋ถ€์ ์œผ๋กœ ํŒ๋‹จํ•œ๋‹ค.

๐Ÿ‘‰ ADO ๋ฐฉ์‹์ฒ˜๋Ÿผ ๊ฐœ๋ฐœ์ž๊ฐ€ ํŠธ๋žœ์žญ์…˜ ์ˆœ์„œ๋ฅผ ํ•˜๋‚˜ํ•˜๋‚˜ ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

๋ณด๋‹ค ๊ฐ•๋ ฅํ•œ ์‚ฌํ•ญ์€ CUD ์—์„œ ๋ฐœ์ƒํ•œ๋‹ค

์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”์— ๊ฑธ์ณ ๊ด€๊ณ„๊ฐ€ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ Insert / Update / Delete ํ•  ๋•Œ ORM ์ด ํŠนํžˆ ๊ฐ•ํ•˜๋‹ค.
์ด์œ ๋Š”, ์—”ํ‹ฐํ‹ฐ ์„ ์–ธ์„ ํ†ตํ•ด ์ด๋ฏธ ORM ํ…Œ์ด๋ธ”๊ฐ„ ์ƒ/ํ•˜ ๊ด€๊ณ„๋ฅผ ์ด๋ฏธ ์•Œ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค

ํ•˜์ง€๋งŒ, ๋ฌธ์ œ๋Š” ์กฐํšŒ(Read)์ด๋‹ค.
๊ธฐ๋ณธ ์กฐํšŒ ์ „๋žต์ด Lazy Loading ์ธ ๊ฒฝ์šฐ N+1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฝ๋‹ค.

Lazy Loading

EF(Entity Framwork)๋Š” Context ์—์„œ ํ•ด๋‹น DB๋ฅผ ๊ธฐ์–ตํ•˜๊ณ  ์žˆ๋‹ค๊ฐ€, ์‹ค์ œ ์ ‘๊ทผ์„ ํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธ ํ›„ DB ์กฐํšŒ๋ฅผ ์‹คํ–‰.

๐Ÿ”น ADO(ADO.NET) ์ด๋ž€?

  • ADO ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ SQL ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•ด์„œ DB ์™€ ํ†ต์‹ ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.
  • ADO ์—์„œ๋Š” ๊ฐ์ฒด๋ณด๋‹ค DB ์™€ ์ฟผ๋ฆฌ๊ฐ€ ์ฃผ์ฒด๋‹ค.

์œ ์ง€๋ณด์ˆ˜ ๊ด€์ 

  1. ORM ์€ ์ฝ”๋“œ๊ฐ€ ๊น”๋”ํ•œ ๋Œ€์‹  ์‹ค์ œ ์ฟผ๋ฆฌ๊ฐ€ ๋ˆˆ์— ์ž˜ ์•ˆ ๋ณด์ด๊ณ 
  2. ADO ๋Š” ์ฟผ๋ฆฌ๊ฐ€ ๊ทธ๋Œ€๋กœ ๋“œ๋Ÿฌ๋‚˜์„œ ์œ ์ง€๋ณด์ˆ˜ ์‹œ DB ๊ด€์ ์—์„œ๋Š” ๋” ์ง๊ด€์ ์ผ ์ˆ˜ ์žˆ๋‹ค.
    (ํ•„์ž๋Š” ADO ๋ฅผ ์‚ฌ์‹ค ๋” ๋งŽ์ด ์ด์šฉํ•œ๋‹ค.)

๊ฒฐ๋ก 

ORM ์€ ๊ฐ์ฒด ์ค‘์‹ฌ ๊ฐœ๋ฐœ๊ณผ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ์— ๊ฐ•์ ์ด ์žˆ๋Š” ๊ธฐ์ˆ ์ด๊ณ 

ORM ์€ ํŽธ๋ฆฌํ•˜์ง€๋งŒ ์กฐํšŒ ์ „๋žต์„ ์ž˜๋ชป ์‚ฌ์šฉํ•˜๋ฉด N+1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๊ณ ,

ADO ๋Š” ์ฟผ๋ฆฌ ์ค‘์‹ฌ์œผ๋กœ ์„ฑ๋Šฅ๊ณผ ๋ช…ํ™•์„ฑ์„ ํ™•๋ณดํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

ADO ๋Š” ์ฟผ๋ฆฌ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜๋Š” ๋งŒํผ ๋” ๋งŽ์€ ๊ณต์ˆ˜๊ฐ€ ๋“ค์ง€๋งŒ ๋Œ€์šฉ๋Ÿ‰ ์กฐํšŒ๋‚˜ ์„ฑ๋Šฅ ์ธก๋ฉด์—์„œ๋Š” ๋” ์•ˆ์ •์ ์ธ ์„ ํƒ์ด ๋  ์ˆ˜ ์žˆ๋‹ค.

ORM ์€ ์ƒ์‚ฐ์„ฑ์„, ADO ๋Š” ์ œ์–ด๊ถŒ๊ณผ ์„ฑ๋Šฅ์„ ์„ ํƒํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€