728x90
📘 Chapter 3.4: 고급 LINQ 커스터마이징 & 쿼리 최적화
✅ 이번 챕터 목표
- LINQ의 내부 작동 방식 이해
- 쿼리식 vs 메서드 체이닝 차이
- IEnumerable vs IQueryable 차이
- Select, Where 커스터마이징 방법
- 실무 성능 개선 전략 (지연 실행, ToList, Projection 등)
1️⃣ LINQ의 기본 개념 다시 정리
LINQ는 2가지 방식으로 쓸 수 있다:
✅ 쿼리식 (Query Syntax)
var result = from x in list
where x > 10
select x * 2;
✅ 메서드 체이닝 (Method Syntax)
var result = list.Where(x => x > 10)
.Select(x => x * 2);
➡️ 내부적으로는 둘 다 메서드 체이닝으로 변환된다
2️⃣ IEnumerable vs IQueryable 차이
항목 | IEnumerable | IQueryable |
---|---|---|
위치 | System.Linq | System.Linq |
대상 | 메모리 내 컬렉션 | DB 등 외부 소스 (EF, OData) |
실행 방식 | C# 코드에서 직접 처리 | SQL 등으로 변환됨 |
실행 시점 | 즉시 or 지연 | 지연 |
장점 | 간단하고 직관적 | 외부 쿼리 최적화 가능 |
✅ 실무 예시 (EF 기준)
IEnumerable<User> users = db.Users.ToList();
var list = users.Where(u => u.Age > 20); // LINQ to Object
IQueryable<User> usersQuery = db.Users;
var query = usersQuery.Where(u => u.Age > 20); // LINQ to SQL
➡️ ToList()를 먼저 쓰면 쿼리가 쪼개져서 성능 저하
→ 반드시 필터 → ToList() 순서로 작성해야 함!
3️⃣ Select, Where 직접 커스터마이징
LINQ는 내부적으로 yield return 기반의 지연 실행(Deferred Execution)을 사용함
✅ 커스텀 Where 구현 예시
public static class MyLinq
{
public static IEnumerable<T> MyWhere<T>(
this IEnumerable<T> source,
Func<T, bool> predicate)
{
foreach (var item in source)
{
if (predicate(item))
yield return item;
}
}
}
var data = new[] { 1, 2, 3, 4, 5 };
var result = data.MyWhere(x => x % 2 == 0);
✅ 지연 실행(Deferred Execution) 확인
var result = data.Where(x =>
{
Console.WriteLine($"검사 중: {x}");
return x % 2 == 0;
});
Console.WriteLine("------");
foreach (var r in result)
{
Console.WriteLine($"결과: {r}");
}
출력:
------
검사 중: 1
검사 중: 2
결과: 2
검사 중: 3
검사 중: 4
결과: 4
검사 중: 5
➡️ foreach 돌리기 전까지는 아무것도 실행 안 됨!
4️⃣ Projection 최적화 (Select vs SelectMany)
- Select는 요소 1:1 변환
- SelectMany는 1:N 펼치기
var customers = new[]
{
new { Name = "A", Orders = new[] { "item1", "item2" } },
new { Name = "B", Orders = new[] { "item3" } },
};
var flat = customers.SelectMany(c => c.Orders);
// 결과: item1, item2, item3
➡️ 실무에서 List 안의 List 펼칠 때 핵심
5️⃣ 실무 성능 개선 전략
전략 | 설명 |
---|---|
ToList() 남용 금지 | 필터 후 ToList 해야 DB 최적화 |
FirstOrDefault() 조심 | IEnumerable는 전부 순회, IQueryable은 SQL 최적화 |
Projection만 가져오기 | Select(x => new { x.Id })로 필요한 필드만 |
Where 대신 Any() | list.Any(x => x.조건)은 더 빠르고 명확 |
✅ LINQ에서 N+1 쿼리 피하기 (EF 예시)
var users = db.Users.Include(u => u.Posts).ToList();
✅ .Include()로 필요한 데이터 한번에 가져오기
✅ 정리 요약
항목 | 요약 |
---|---|
LINQ 종류 | 쿼리식, 메서드 체이닝 → 결국 메서드 방식 |
IEnumerable | 메모리 내 처리 (ToList() 이후) |
IQueryable | DB 처리 (지연 실행 & SQL 변환) |
커스터마이징 | Select/Where 직접 구현 가능 |
실무 팁 | ToList 남용 금지, Projection 사용 권장 |
📢 다음 챕터 예고 🎓
Chapter | 주제 |
---|---|
3.5 | 코드 분석 및 성능 측정 도구 사용 (BenchmarkDotNet 등) |
728x90
'C#' 카테고리의 다른 글
C# 기초부터 고급까지 Chapter 3.6. .NET 메모리 관리 이해 – GC 동작 원리 (2) | 2025.05.10 |
---|---|
C# 기초부터 고급까지 Chapter 3.5. 코드 분석 및 성능 측정 도구 사용 (BenchmarkDotNet 등) (2) | 2025.05.07 |
C# 기초부터 고급까지 Chapter 3.3. Expression Tree로 컴파일 타임 코드 생성 (17) | 2025.05.05 |
C# 기초부터 고급까지 Chapter 3.2. Reflection & Dynamic Type – 런타임 메타프로그래밍 (0) | 2025.05.05 |
C# 기초부터 고급까지 Chapter 3.1. Span , Memory , Unsafe – 퍼포먼스 챙기는 C# 코드 (0) | 2025.05.04 |