Tốc độ xử lý của iqueryable và ienumerable

bởi Bạch Ngọc Toàn vào 15/06/2016. Lượt xem: 45,403

LINQ dùng để truy vấn dữ liệu từ cơ sở dữ liệu và các collection, chúng ta sử dụng IEnumerable và IQueryable để thao tác dữ liệu nhưng một số bạn vẫn chưa hiểu được sự khác nhau giữa 2 đối tượng này. IQueryable kế thừa IEnumerable, vì thế IQueryable có tất cả các đặc tính của IEnumerable và có thêm các đặc tính của riêng nó. Cả hai đều mang tính quan trọng khi truy vấn và thao tác dữ liệu. Chúng ta hãy cùng xem các tính năng của cả hai và so sánh chúng để dùng trong trường hợp nào cho hợp lý nhất nhé.

IEnumerable

  1. IEnumerable nằm trong namespace System.Collections
  2. IEnumerable có thể duyệt cac phần tử chỉ 1 chiều tiến lên, nó không thể duyệt ngược lại giữa các phần tử.
  3. IEnumerable tốt nhất khi truy vấn từ một collection in-memory tức là trong bộ nhớ RAM như List, Array…
  4. Khi truy vấn dữ liệu từ database, IEnumerable thực thi câu lệnh select trên server sau đó tải toàn bộ dữ liệu về client rồi mới lọc dữ liệu.
  5. IEnumerable phù hợp với Linq to Object và Linq to XML
  6. IEnumerable không hỗ trợ custom query
  7. IEnumerable không hỗ trợ lazy loading vì thế không phù hợp với trường hợp phân trang.

Ví dụ về IEnumerable

MyDataContext dc = new MyDataContext ();
IEnumerable list = dc.Employees.Where(p => p.Name.StartsWith("S"));
list = list.Take(10);

Câu lệnh của đoạn code trên sẽ gen ra như sau:

SELECT [t0].[EmpID], [t0].[EmpName], [t0].[Salary] FROM [Employee] AS [t0]
WHERE [t0].[EmpName] LIKE @p0

Chú ý là trong câu lệnh này “top 10” sẽ không có vì IEnumerable lọc các bản ghi ở dưới client. Nên toàn bộ số bản ghi trước khi load ra top 10 sẽ dc tải về client.

IQueryable

  1. IQueryable nằm trong namespace System.Linq
  2. IQueryable cũng chỉ có thể di chuyển 1 chiều tiến lên trong collection, nó không thể move back lại.
  3. IQueryable tốt nhất cho truy vấn dữ liệu out-memory như là database.
  4. Khi truy vấn, IQueryable thực thi câu lệnh truy vấn và lọc dữ liệu trên Server luôn
  5. IQueryable phù hợp cho Linq to SQL
  6. IQueryable hỗ trợ custom query sử dụng phương thức CreateQuery và Execute.
  7. IQueryable hỗ trợ lazy loading. Vì thế nó phù hợp cho trường hợp phân trang.Ví dụ về IQueryable

Ví dụ về IQueryable

MyDataContext dc = new MyDataContext ();
IQueryable list = dc.Employees.Where(p => p.Name.StartsWith("S"));
list = list.Take(10);

Câu lệnh gen ra sẽ như sau:

SELECT TOP 10 [t0].[EmpID], [t0].[EmpName], [t0].[Salary] FROM [Employee] AS [t0]
WHERE [t0].[EmpName] LIKE @p0

Chú ý: Câu lệnh trên có chữa “top 10” vì IQueryable thực  thi câu lệnh và lọc dữ liệu trên server hoàn toàn. Chỉ khi gọi ToList() hoặc đưa vào duyệt thì nó mới thực thi.

Tổng kết

Trong bài viết này mình cố gắng giải thích sự khác nhau giữa IEnumerable và IQueryable. Iqueryable giúp cho các bạn build câu lệnh và thực thi 1 lần trên server để trả về số bản ghi nhỏ nhất có thể. Còn IEnumerable giúp các bạn thao tác với các collection in-memory sẽ tốt hơn. Mình hy vọng sau khi đọc xong bài viết này các bạn có thể tăng khả năng sử dụng 2 đối tượng này giúp tăng performance. Nếu có feedback gì về bài viết vui lòng comment phía dưới.

Trích nguồn từ: (dotnet-tricks.com)

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:

Tốc độ xử lý của iqueryable và ienumerable

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.