2015-12-03 12 views
5

Tôi có một danh sách các đối tượng mà tôi muốn giảm xuống chỉ những đối tượng có thuộc tính chứa trong một danh sách riêng biệt.Chứa danh sách quá chậm, cách cải thiện?

List1 là danh sách các chuỗi đơn giản.

List2 là danh sách các đối tượng có chứa hai thuộc tính chuỗi; A và B.

Tất cả các mục trong đó A B không có trong Danh sách 1, phải được loại bỏ.

Quá trình này phụ thuộc rất nhiều thời gian và cần phải nhanh nhất có thể. Hiện tại tôi có triển khai sau;

var List1 = new List<String>() {"Around", "9000", "strings"}; //List of about 9000 strings 
var List2 = databaseList.ToList(); //Around 2.5 million objects 

var reducedList = new HashSet<Object>();    
foreach (var item in List2) 
{ 
    if(List1.Contains(item.A) && List1.Contains(item.B)) 
    { 
     reducedList.Add(item); 
    } 
} 

Quá trình này mất khoảng 7 giây để hoàn thành, yêu cầu hiện tại của tôi quá chậm.

Tôi đã thử chạy tính năng này bằng LINQ, nhưng cho kết quả tương tự, khoảng 7 giây.

var reducedList = List2.Where(r => List1.Contains(r.A)).Where(r => List1.Contains(r.B)).ToList(); 

Bất kỳ đề xuất nào về những gì tôi có thể làm để cải thiện điều này?

EDIT: Tôi không thể làm được điều này ở phía bên SQL của sự vật, kể từ 9000 chuỗi mà tôi cần phải so sánh với không thể được "dịch" vào và SQL truy vấn, nhưng sẽ đi phía trên cho phép 2100 tham số đầu vào được cho phép trong thiết lập SQL Server của chúng tôi.

+7

[HashSet] (https://www.google.com/search?q=hashset&ie=utf-8&oe=utf-8). –

+0

Mất bao lâu ** chỉ ** thực hiện 'foreach' trên tất cả các mục trong cơ sở dữ liệu? Bạn có định thời gian vòng lặp 'foreach', hoặc hai câu lệnh khởi tạo không? –

+3

Việc tìm kiếm trên cơ sở dữ liệuList chứa hơn 2,5 triệu đối tượng là những gì làm phiền tôi; cũng được đặt tên (databaseList) là bạn chắc chắn bạn không thể thực hiện truy vấn ở cấp db? –

Trả lời

0

Như đã chỉ bởi @Ondrej Svejdar, nếu databaseList đến từ EntityFramework, bạn thì bạn nên không gọi ToList(), vì nó làm cho một truy vấn db, mà trở lại 2,5 triệu hồ sơ

var reducedList = databaseList 
       .Where(r => List1.Contains(r.A) && List1.Contains(r.B)) 
       .ToList(); 

Ngoài ra nếu List1 xuất phát từ cơ sở dữ liệu (Tôi hy vọng là 9000 là một số lớn để xây dựng bằng tay), sau đó xem xét sử dụng toán tử join.

+1

Nếu 'List1' là một danh sách trong bộ nhớ, thì 9000 mục sẽ được dịch sang các tham số SQL, có thể sẽ không biên dịch (không phải trong SQL Server). – Maarten

2

Đầu tiên, Hãy làm cho danh sách đầu tiên nhanh hơn để tra cứu trên:

var sought = new HashSet<String>() {"Around", "9000", "strings"}; 

Cũng tại sao bận tâm kéo tạo một danh sách trong bộ nhớ nếu bạn chỉ đi lặp qua nó. Trừ khi bạn sẽ muốn sử dụng List2 cho một số mục đích khác, nó không làm bất cứ điều gì.

foreach (var item in databaseList) 
{ 
    if(sought.Contains(item.A) && sought.Contains(item.B)) 
    { 
    reducedList.Add(item); 
    } 
} 

Đồng thời nhập reducedList danh sách băm thích hợp là new HashList<TheActualTypeOfTheItemsHere>.

Nếu loại đó không triển khai IEquatable<T> thì hãy thêm triển khai đó. Nếu điều đó là không thể, hãy tạo một IEqualityComparer<T> thích hợp và sử dụng nó trong hàm tạo của reducedList.

+0

Danh sách có 9000 chuỗi sẽ được dịch thành 9000 tham số và SQL giống như “WHERE item.A = value1 OR item.A = value2 OR ...'. SQL Server cũng không hỗ trợ nhiều tham số. – Maarten

+0

@ Marta heh. Tôi thậm chí còn không nhìn vào những sợi dây thực sự và nghĩ đến bản thân mình "ừm, nếu chỉ có một vài chuỗi trong danh sách đầu tiên ..."! –

+0

@Maarten một chút saner bây giờ cho rằng sử dụng. –

3

Tôi chưa thử nhưng có lẽ nó sẽ tăng hiệu suất.

var List1 = new List<String>() {"Around", "9000", "strings"}; 
var List2 = databaseList.ToList(); //Around 2.5 million objects 

var reducedList = List2.RemoveAll(i => !List1.Contains(i.A) && !List1.Contains(i.B)).ToList(); 
+0

'Danh sách .RemoveAll (Predicate )' trả về một int, không phải là một danh sách, do đó, điều này không biên dịch. Ngoài ra, '.Contains (...)' vẫn được thực hiện, vậy tại sao điều này lại tốt hơn? – Maarten

0

Các phiên bản của cơ sở dữ liệu của bạn có thể là một vấn đề: tham khảo: Slower sqlite Kể từ khi tôi không biết những gì vua của DB bạn đang sử dụng, điều này có thể là "vô dụng".Nhưng hãy xem liệu DB của bạn có phiên bản mới nhất hay không và cũng có thể xem nhanh như thế nào. Kiểm tra chương trình của bạn trên một máy tính/trình duyệt/điện thoại khác và xem bạn có nhận được kết quả tương tự hay không.

Bây giờ bạn nên tìm NHỮNG GÌ chính xác là mất nhiều thời gian. Hãy thử xóa câu lệnh if của bạn và xem tốc độ có cải thiện hay không. Nếu nó không cải thiện nó là truy vấn tốc độ đó là một vấn đề. Nếu có, hãy thử truy vấn DB của bạn theo cách bạn không cần sử dụng nếu.

0

Bạn có thể thử thực hiện IEquatable trên đối tượng của bạn, vì nó là phương pháp mà Contains sẽ gọi để xem nếu đối tượng nằm trong danh sách

Xem post này cho biết thêm.

0

Danh sách 1 thường lớn đến mức nào? Nếu đó là một danh sách nhỏ như trong mẫu của bạn, sau đó ở lại với một danh sách sẽ là tốt. Nếu đó không phải là trường hợp, bạn có thể nhận được kết quả tốt hơn với một HashSet thay thế.

Trình thay đổi trò chơi thực sự, tôi tin là tránh tải List2 với 2,5 triệu đối tượng, chỉ để lọc chúng sau này. Nếu databaseList là một số loại IEnumerable đến một DbSet, bạn có thể có được kết quả tốt hơn với một cái gì đó như:

var List1 = new List<String>() {"Around", "9000", "strings"}; 
var reducedList = (from item in databaseList 
        where List1.Contains(item.A) && List1.Contains(item.B) 
        select item).ToList(); 

Sử dụng một HashSet cho danh sách giảm của bạn sẽ chỉ làm chậm chèn. Nếu bạn đang sử dụng nó để tránh trùng lặp, hoặc để tăng tốc độ tra cứu sau đó, sau đó bạn nên giữ nó. Nếu không thì Danh sách sẽ tốt hơn.

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