Tôi đang làm việc trên một đoạn mã, được viết bởi đồng nghiệp, giao diện với ứng dụng CRM mà công ty chúng tôi sử dụng. Có hai truy vấn LINQ to Entities trong đoạn mã này được thực hiện nhiều lần trong ứng dụng của chúng tôi và tôi đã được yêu cầu tối ưu hóa chúng vì một trong số chúng thực sự chậm.Truy vấn LINQ to Entities mất nhiều thời gian để biên dịch, SQL chạy nhanh
Đây là các truy vấn:
Truy vấn đầu tiên, tính năng này biên dịch ngay lập tức. Nó lấy thông tin liên quan từ cơ sở dữ liệu CRM, lọc theo một danh sách các ID liên quan đưa ra bởi các ứng dụng:
from relation in context.ADRELATION
where ((relationIds.Contains(relation.FIDADRELATION)) && (relation.FLDELETED != -1))
join addressTable in context.ADDRESS on relation.FIDADDRESS equals addressTable.FIDADDRESS
into temporaryAddressTable
from address in temporaryAddressTable.DefaultIfEmpty()
join mailAddressTable in context.ADDRESS on relation.FIDMAILADDRESS equals
mailAddressTable.FIDADDRESS into temporaryMailAddressTable
from mailAddress in temporaryMailAddressTable.DefaultIfEmpty()
select new { Relation = relation, Address = address, MailAddress = mailAddress };
Các truy vấn thứ hai, trong đó có khoảng 4-5 giây để biên dịch, và lấy thông tin về những người từ cơ sở dữ liệu (một lần nữa được lọc theo danh sách các ID):
from role in context.ROLE
join relationTable in context.ADRELATION on role.FIDADRELATION equals relationTable.FIDADRELATION into temporaryRelationTable
from relation in temporaryRelationTable.DefaultIfEmpty()
join personTable in context.PERSON on role.FIDPERS equals personTable.FIDPERS into temporaryPersonTable
from person in temporaryPersonTable.DefaultIfEmpty()
join nationalityTable in context.TBNATION on person.FIDTBNATION equals nationalityTable.FIDTBNATION into temporaryNationalities
from nationality in temporaryNationalities.DefaultIfEmpty()
join titelTable in context.TBTITLE on person.FIDTBTITLE equals titelTable.FIDTBTITLE into temporaryTitles
from title in temporaryTitles.DefaultIfEmpty()
join suffixTable in context.TBSUFFIX on person.FIDTBSUFFIX equals suffixTable.FIDTBSUFFIX into temporarySuffixes
from suffix in temporarySuffixes.DefaultIfEmpty()
where ((rolIds.Contains(role.FIDROLE)) && (relation.FLDELETED != -1))
select new { Role = role, Person = person, relation = relation, Nationality = nationality, Title = title.FTXTBTITLE, Suffix = suffix.FTXTBSUFFIX };
Tôi đã thiết lập SQL Profiler và lấy SQL từ cả hai truy vấn, sau đó chạy nó trong SQL Server Management Studio. Cả hai truy vấn đều chạy rất nhanh, ngay cả với số ID lớn (~ 1000). Vì vậy, vấn đề dường như nằm trong quá trình biên dịch truy vấn LINQ.
Tôi đã thử sử dụng truy vấn đã biên dịch, nhưng vì chúng chỉ có thể chứa các tham số nguyên thủy, tôi phải loại bỏ phần đó bằng bộ lọc và áp dụng sau cuộc gọi Invoke(), vì vậy tôi không chắc chắn giúp nhiều. Ngoài ra, kể từ khi mã này chạy trong một hoạt động dịch vụ WCF, tôi không chắc chắn nếu các truy vấn được biên dịch thậm chí sẽ vẫn còn tồn tại trên các cuộc gọi tiếp theo.
Cuối cùng những gì tôi đã thử là chỉ chọn một cột trong truy vấn thứ hai. Mặc dù điều này rõ ràng sẽ không cung cấp cho tôi thông tin tôi cần, nhưng tôi nghĩ nó sẽ nhanh hơn ~ 200 cột mà chúng tôi đang chọn bây giờ. Không có trường hợp như vậy, nó vẫn mất 4-5 giây.
Tôi không phải là chuyên gia LINQ, vì vậy tôi hầu như không thể theo mã này (tôi có cảm giác nó không được viết tối ưu, nhưng không thể đặt ngón tay của tôi lên đó). Bất cứ ai có thể cho tôi một gợi ý là tại sao vấn đề này có thể xảy ra?
Giải pháp duy nhất tôi còn lại là chọn thủ công tất cả thông tin thay vì tham gia tất cả các bảng này. Sau đó tôi sẽ kết thúc với khoảng 5-6 truy vấn. Không quá tệ, tôi đoán, nhưng vì tôi không giao dịch với SQL không hiệu quả khủng khiếp ở đây (hoặc ít nhất là một mức độ không thể chấp nhận được), tôi đã hy vọng để ngăn chặn điều đó.
Cảm ơn trước, hy vọng tôi đã làm mọi thứ rõ ràng. Nếu không, vui lòng hỏi và tôi sẽ cung cấp thêm chi tiết.
Edit: tôi đã kết thúc thêm các hiệp hội về khuôn khổ thực thể của tôi (cơ sở dữ liệu mục tiêu không có phím nước ngoài quy định) và viết lại các truy vấn thusly:
context.ROLE.Where(role => rolIds.Contains(role.FIDROLE) && role.Relation.FLDELETED != -1)
.Select(role => new
{
ContactId = role.FIDROLE,
Person = role.Person,
Nationality = role.Person.Nationality.FTXTBNATION,
Title = role.Person.Title.FTXTBTITLE,
Suffix = role.Person.Suffix.FTXTBSUFFIX
});
vẻ hơn rất nhiều có thể đọc được và nó cũng nhanh hơn.
Cảm ơn bạn đã đề xuất, tôi chắc chắn sẽ giữ nguyên việc tạo nhiều truy vấn được biên dịch cho số lượng đối số khác nhau!
Như tôi đã nói về câu trả lời của Gabriel GM, tôi đã đặt chúng trong một trường tĩnh. Tôi sẽ thử lại chỉ để chắc chắn 110%, tôi đoán vậy. Điều đó sẽ làm việc mặc dù, vì tôi sẽ chỉ có thể đặt một phần lên đến mệnh đề where trong truy vấn được biên dịch? –
Tôi đã thêm nhiều nội dung khác. – usr
Ồ, ý tưởng tuyệt vời về điều bản thân! Bạn nói đúng, hầu hết các yêu cầu sẽ có ít hơn 10 id vai trò. Chắc chắn một cái gì đó để xem xét. Cảm ơn! –