C# LINQ 쿼리 작성법: 지연 실행과 SQL 차이 이해하기
LINQ는 C# 컬렉션과 데이터 원본을 일관된 문법으로 조회하게 해주지만 SQL 문자열을 실행하는 기능과 같지는 않습니다. 쿼리가 언제 실행되는지, 어떤 공급자가 해석하는지, 결과를 한 번 고정해야 하는지를 먼저 이해해야 해요.


LINQ는 C# 컬렉션과 데이터 원본을 일관된 문법으로 조회하게 해주지만 SQL 문자열을 실행하는 기능과 같지는 않습니다. 쿼리가 언제 실행되는지, 어떤 공급자가 해석하는지, 결과를 한 번 고정해야 하는지를 먼저 이해해야 해요.
쿼리 구문은 컴파일 과정에서 메서드 호출로 바뀐다
from item in items where item.Score >= 80 select item.Name 같은 구문은 읽기 친숙하지만, 컴파일러는 Where와 Select 같은 표준 쿼리 연산자 호출로 변환합니다. 쿼리 구문과 메서드 구문 가운데 하나가 더 빠르다고 단정하기보다 팀이 읽기 쉬운 형태와 필요한 연산자를 기준으로 고르세요.
모든 연산자가 쿼리 키워드로 제공되는 것은 아니어서 Count, ToList 같은 메서드를 뒤에 연결하는 경우가 많습니다. 한 쿼리 안에서 두 형태를 섞어도 되지만 변환 단계가 길어지면 중간 변수와 의미 있는 이름으로 나누는 편이 좋습니다.
지연 실행은 결과를 읽는 순간 원본을 다시 볼 수 있다
IEnumerable<T>를 반환하는 많은 LINQ 연산은 쿼리를 선언할 때가 아니라 foreach로 열거할 때 실행됩니다. 선언 뒤 원본 컬렉션이 바뀌면 결과도 달라질 수 있고, 같은 쿼리를 두 번 열거하면 작업도 두 번 수행될 수 있어요. 특정 시점의 결과가 필요하면 ToList나 ToArray로 구체화합니다.
즉시 실행은 편하지만 데이터가 큰 경우 메모리를 사용합니다. 지연 실행이 항상 좋거나 ToList가 항상 나쁜 것이 아니라, 결과를 몇 번 읽는지와 원본이 변하는지를 보고 선택해야 합니다.
LINQ to Objects와 데이터베이스 LINQ는 실행 위치가 다르다
List<T>를 대상으로 하면 .NET 코드가 메모리에서 실행됩니다. IQueryable 공급자를 쓰는 ORM에서는 식 트리를 SQL 같은 원격 쿼리로 번역할 수 있어요. 모든 C# 메서드가 번역되는 것은 아니며, 번역 실패나 예상보다 큰 데이터 전송이 생길 수 있습니다.
데이터베이스 쿼리는 생성된 SQL, 필터 적용 위치, 실행 횟수를 로그로 확인하세요. SQL과 모양이 비슷하다는 이유로 성능까지 같다고 생각하면 안 됩니다.
var names = students
.Where(student => student.Score >= 80)
.OrderBy(student => student.Name)
.Select(student => student.Name)
.ToList();적용 전에 확인할 체크리스트
기존 화면은 작성 당시의 기록으로 보존했습니다. 현재 작업에서는 제품·서비스·언어 버전과 공식 문서의 적용 대상을 먼저 맞추세요. 설정이나 코드를 한 번에 크게 바꾸지 말고, 변경 전 상태를 기록한 뒤 작은 예제로 결과를 확인하는 편이 안전합니다.
문제가 생기면 같은 조작을 반복하기보다 정확한 오류 문구, 사용 버전, 재현 단계, 기대한 결과와 실제 결과를 적어 두세요. 공개된 캡처에는 계정 주소, 비밀 키, 일련번호처럼 악용될 수 있는 정보가 없는지도 확인합니다.
자주 묻는 질문
기존 게시일과 URL은 바뀌나요?
아니요. 기존 글을 같은 URL에서 보완했으므로 과거 기록과 연결은 유지됩니다.
예전 화면과 현재 화면이 다르면 무엇을 따라야 하나요?
이미지는 당시 맥락을 이해하는 참고 자료로 보고, 실제 조작은 현재 버전의 공식 문서와 화면 문구를 기준으로 하세요.
한 번 확인한 뒤 계속 같은 방법을 써도 되나요?
버전과 정책이 바뀔 수 있습니다. 업데이트 뒤에는 핵심 동작과 보안 조건을 다시 확인해야 합니다.
공식 자료
이 글은 기존 게시물의 URL과 이미지 기록을 유지하면서, 현재 독자가 잘못 적용하기 쉬운 부분을 공식 자료에 맞춰 다시 정리했습니다.
댓글
댓글 쓰기