2012-12-18 24 views
5

Tôi có một bảng 200.000 bản ghi mà tôi chỉ nhận được 10 đầu trang sử dụng .Take() nhưng mất khoảng 10 giây để lấy dữ liệu.LINQ đối với các thực thể rất chậm sử dụng phương thức .Take()

Câu hỏi của tôi là: phương pháp .Take() lấy tất cả dữ liệu từ cơ sở dữ liệu và lọc 10 dữ liệu hàng đầu ở phía máy khách?

Đây là mã của tôi:

mylist = (from mytable in db.spdata().OrderByDescending(f => f.Weight) 
            group feed by mytable.id into g 
            select g.FirstOrDefault()).Take(10).ToList(); 

spdata() là một chức năng nhập khẩu từ thủ tục lưu trữ.

Cảm ơn

+7

Nếu bạn tò mò những gì nó chạy chống lại cơ sở dữ liệu, bạn nên treo một hồ sơ lên đến DB của bạn và kiểm tra nhật ký, đó là cách tốt nhất để tìm hiểu. – Chris

+1

Nếu spdata() trả về 200.000 thì có, nó sẽ làm điều đó ở phía máy khách. –

+0

Ngoài phương thức của Chris, bạn cũng có thể thử Linqpad và chuyển sang chế độ xem SQL sau khi viết truy vấn của bạn để xem SQL được tạo hoặc đặt điểm ngắt (với phương pháp này http://stackoverflow.com/questions/1412863/how -do-i-view-the-sql-tạo-by-the-thực thể-khuôn khổ) để xem những gì được tạo ra khi chương trình thực thi. –

Trả lời

8

Quy trình được lưu trữ có thể trả về rất nhiều dữ liệu cho khách hàng rất chậm. Bạn không thể truy vấn từ xa đến một sproc. Điều đó có thể thực hiện được bằng cách sử dụng một khung nhìn hoặc một hàm có giá trị bảng.

Không có cách nào để sử dụng sproc trong truy vấn. Bạn chỉ có thể tự thực thi nó.

Ý định của bạn có thể là thực hiện Take(10) trên máy chủ. Để làm việc đó, bạn cần chuyển sang truy vấn nội tuyến, chế độ xem hoặc TVF.

6

Các phương pháp khuyến nông Take không không lấy tất cả các kết quả từ cơ sở dữ liệu. Đó không phải là cách hoạt động của Take.

Tuy nhiên, cuộc gọi db.spdata() của bạn có thể tìm nạp tất cả các hàng.

1

Tôi không chắc chắn 100% nhưng như tôi nhớ bạn nhận được một kết quả IEnumerable khi bạn gọi một SP sử dụng EF DataContext ...

Có một vài là để tối ưu hóa hiệu suất:

  • Vượt qua các tiêu chí tìm kiếm là tham số SP và thực hiện việc lọc theo quy trình được lưu trữ.

Hoặc nếu bạn có một truy vấn khá đơn giản trong SP nơi bạn không khai báo bất kỳ biến và nơi bạn đang chỉ tham gia một số bảng sau đó:

  • Tạo một cái nhìn được lập chỉ mục nơi chỉ định truy vấn mà bạn cần và gọi phương thức Take trên đó.
    Điều này sẽ cung cấp cho bạn điều gì? Bạn có thể ánh xạ tới khung nhìn đã tạo và EF giờ đây sẽ trả lại kết quả IQueryable và không phải là một IEnumerable. Điều này sẽ tối ưu hóa lệnh sql và thay vì nhận tất cả dữ liệu và sau đó lấy 10 phần tử mà bạn cần, một lệnh sql chỉ truy xuất 10 phần tử sẽ được tạo thành.

Tôi cũng khuyên bạn nên xem sự khác biệt giữa IEnumerable và IQueryable là gì.

0

Điều này có nghĩa là vì bạn sắp xếp dữ liệu trước khi nhóm, không thể thực hiện trong SQL.

Bạn nên sử dụng một số tổng hợp để có được trọng lượng cao nhất từ ​​mỗi nhóm, sau đó sắp xếp các trọng để có được mười lớn nhất:

mylist = (
    from mytable in db.spdata() 
    group feed by mytable.id into g 
    select g.Max(f => f.Weight) 
).OrderByDescending(w => w).Take(10).ToList(); 
+0

nó đưa ra một lỗi Lỗi "Một biến cục bộ có tên 'g' không thể được khai báo trong phạm vi này bởi vì nó sẽ đưa ra một ý nghĩa khác với 'g', đã được sử dụng trong phạm vi 'mẹ hoặc hiện tại' để biểu thị cái gì khác" –

+0

@AliIssa: Phải, nó phải là một biến khác ở đó. Tôi đã thay đổi nó. – Guffa

Các vấn đề liên quan