Coder Có Biết IEnumerable Và IQueryable Khác Nhau Thế Nào?

Coder Có Biết IEnumerable Và IQueryable Khác Nhau Thế Nào?

Như chúng ta đã biết, LINQ - Ngôn ngữ truy vấn tích hợp, được sử dụng để truy vấn dữ liệu từ một tập hợp dữ liệu. Tập hợp dữ liệu có thể là trong cơ sở dữ liệu hoặc collection trên bộ nhớ... Khi sử dụng LINQ, chúng ta có lẽ bắt gặp việc sử dụng IEnumerable và IQueryable rất nhiều nhưng lại chưa hiểu được sự khác biệt giữa chúng. Trong bài viết này, tôi sẽ chia sẻ với các bạn một số điểm lưu ý khi sử dụng 2 interface trên.

Bài toán đặt ra

Để thấy được sự khác biệt giữa 2 interface trên tôi sẽ sử dụng LINQ trong việc truy vấn dữ liệu từ cơ sở dữ liệu (Sql Server). Tôi có bảng Users với dữ liệu như sau:



Bài toán đặt ra là hãy tìm các user có UserId >= 5.

Tôi sử dụng Sql Server Profile để xác định câu lệnh truy vấn được gửi từ client tới server.

Sự khác nhau giữa IEnumerable và IQueryable

Về khái niệm của IEnumerable, tôi đã có bài giới thiệu về nó. Các bạn có thể tham khảo tại đây.

Về khái niệm của IQueryable, được implement từ IEnumerable nên IQueryable có tất cả các đặc tính của IEnumerable và các đặc tính của riêng nó. Cả 2 interface này rất quan trọng trong quá trình truy vấn và thao tác tới dữ liệu. Chúng ta hãy xem sự khác nhau giữa 2 interface qua bảng dưới đây.

Item IEnumerable IQueryable
Namespace System.Collections System.Linq
Duyệt phần tử Duyệt phần tử theo chiều tiến lên. Duyệt phần tử theo chiều tiến lên.
Truy vấn tốt nhất Truy vấn tốt nhất đối với những dữ liệu trên bộ nhớ như List, Array... Truy vấn tốt nhất đối với những dữ liệu nằm ngoài bộ nhớ như cơ sở dữ liệu.
Cách thức truy vấn Truy vấn trên server và trả về dữ liệu cho client. Client sau đấy mới tiếp tục lọc dữ liệu. Truy vấn và lọc dữ liệu trên server và dữ liệu trả về cho client.

Chúng ta hãy lưu ý đến cách thức truy vấn qua đoạn mã sau:

class Program
    {
        static void Main(string[] args)
        {
            var entities = new DataEntities();

            // Khối 1
            var enumerableUsers = entities.Users.AsEnumerable().Where(f => f.UserId >= 5).Take(2);
            foreach (var item in enumerableUsers)
            {
                Console.WriteLine(item.UserId);
            }

            // Khối 2
            var queryableUsers = entities.Users.Where(f => f.UserId >= 5).Take(2);
            foreach (var item in queryableUsers)
            {
                Console.WriteLine(item.UserId);
            }

            Console.ReadKey();
        }
    }

Cả 2 phần tìm kiếm đều trả về kết quả là:

5
6

Giờ chúng ta hãy mở Sql Profile và thấy Sql Engine thực hiện 2 câu lệnh như sau:

SELECT 
    [Extent1].[UserId] AS [UserId], 
    [Extent1].[Username] AS [Username], 
    [Extent1].[Password] AS [Password], 
    [Extent1].[Fullname] AS [Fullname], 
    [Extent1].[State] AS [State]
    FROM [dbo].[Users] AS [Extent1]

Khi thực hiện Khối 1.

SELECT TOP (2) 
    [Extent1].[UserId] AS [UserId], 
    [Extent1].[Username] AS [Username], 
    [Extent1].[Password] AS [Password], 
    [Extent1].[Fullname] AS [Fullname], 
    [Extent1].[State] AS [State]
    FROM [dbo].[Users] AS [Extent1]
    WHERE [Extent1].[UserId] >= 5

Khi thực hiện Khối 2.

Khi sử dụng IEnumerable, câu lệnh truy vấn sẽ thực hiện trên máy chủ và trả về dữ liệu cho client. Sau khi trả hết dữ liệu, client mới thực hiện lấy 2 bản ghi đầu tiên.

Khi sử dụng IQueryable, câu lệnh truy vấn sẽ thực hiện trên máy chủ, lọc trên máy chủ và trả dữ liệu cho client.

Trong điều kiện số bản ghi của bảng Users lớn thì việc sử dụng IEnumerable sẽ ảnh hưởng rất nhiều tới hiệu năng của ứng dụng cũng như của Sql Server.

Tạm kết

Đến đây các bạn cũng đã hiểu sự khác nhau giữa IEnumerable và IQueryable. Rất mong sự góp ý nhỏ của mình sẽ có ích cho các bạn.