Почему этот LINQ намного медленнее, чем его аналог SQL? - PullRequest
0 голосов
/ 06 октября 2010

У меня есть следующий LINQ to SQL метод, выполнение которого занимает слишком много времени, но его аналог SQL довольно прост и быстр.Я делаю что-то не так в части LINQ?Я просто пытаюсь вернуть некоторые данные для отображения, только для чтения, в сетке данных.

Я понимаю, что если инструмент не подходит, не используйте его, и поэтому я мог бы просто сделать SQL-вызов здесь, но я хотел бы понять, почему есть такая разница.

Ниже приведено LINQ, а затем SQL, который он создает.

    public static DataTable GetEnrolledMembers(Guid workerID)
    {
        using (var DB = CmoDataContext.Create())
        {                
            var AllEnrollees = from enrollment in DB.tblCMOEnrollments
                               where enrollment.CMOSocialWorkerID == workerID || enrollment.CMONurseID == workerID
                               join supportWorker in DB.tblSupportWorkers on enrollment.EconomicSupportWorkerID
                                   equals supportWorker.SupportWorkerID into workerGroup
                               from worker in workerGroup.DefaultIfEmpty()
                               select
                                   new
                                       {
                                           enrollment.ClientID,
                                           enrollment.CMONurseID,
                                           enrollment.CMOSocialWorkerID,
                                           enrollment.EnrollmentDate,
                                           enrollment.DisenrollmentDate,
                                           ESFirstName = worker.FirstName,
                                           ESLastName = worker.LastName,
                                           ESPhone = worker.Phone
                                       };

            var result = from enrollee in AllEnrollees.AsEnumerable()
                         where (enrollee.DisenrollmentDate == null || enrollee.DisenrollmentDate > DateTime.Now)
                         let lastName = BLLConnect.MemberLastName(enrollee.ClientID)
                         let firstName = BLLConnect.MemberFirstName(enrollee.ClientID)
                         orderby enrollee.DisenrollmentDate ascending , lastName ascending
                         select new
                             {
                                 enrollee.ClientID,
                                 LastName = lastName,
                                 FirstName = firstName,
                                 NurseName = BLLAspnetdb.NurseName(enrollee.CMONurseID),
                                 SocialWorkerName = BLLAspnetdb.SocialWorkerName(enrollee.CMOSocialWorkerID),
                                 enrollee.EnrollmentDate,
                                 enrollee.DisenrollmentDate,
                                 ESWorkerName = enrollee.ESFirstName + " " + enrollee.ESLastName,
                                 enrollee.ESPhone
                             };

            DB.Log = Console.Out;
            return result.CopyLinqToDataTable();
        }
    }

И SQL:

SELECT [t0].[ClientID], [t0].[CMONurseID], [t0].[CMOSocialWorkerID], [t0].[EnrollmentDate], [t0].[DisenrollmentDate], [t1].[FirstName] AS [ESFirstName], [t1].[LastName] AS [ESLastName], [t1].[Phone] AS [ESPhone]
FROM [dbo].[tblCMOEnrollment] AS [t0]
LEFT OUTER JOIN [dbo].[tblSupportWorker] AS [t1] ON [t0].[EconomicSupportWorkerID] = ([t1].[SupportWorkerID])
WHERE ([t0].[CMOSocialWorkerID] = @p0) OR ([t0].[CMONurseID] = @p1)
-- @p0: Input UniqueIdentifier (Size = 0; Prec = 0; Scale = 0) [060632ee-be09-4057-b17b-2d0190d0ff74]
-- @p1: Input UniqueIdentifier (Size = 0; Prec = 0; Scale = 0) [060632ee-be09-4057-b17b-2d0190d0ff74]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.30729.4926

Ответы [ 2 ]

4 голосов
/ 06 октября 2010

Добавляя AsEnumerable():

var result = from enrollee in AllEnrollees.AsEnumerable()
            ...

Вы заставляете первый запрос полностью оцениваться и каждую запись (AllEnrollees) извлекать из БД.

С помощью оператора SQL вы выполняете всю фильтрацию на сервере, которая будет намного быстрее.

1 голос
/ 06 октября 2010

Во-первых, я не думаю, что вы сравниваете яблоки с яблоками, у вас достаточно BllConnect. Что-то вызывает выбор второго запроса linq.Кроме того, вы должны убрать AsEnumerable, как упомянуто в другом ответе.

Примите во внимание следующее (если вы добавите соответствующие отношения в конструктор db и / или linq2sql):

public static DataTable GetEnrolledMembers(Guid workerID)
{
    using (var DB = CmoDataContext.Create())
    {                
        var AllEnrollees = from enrollment in DB.tblCMOEnrollments
                           where enrollment.CMOSocialWorkerID == workerID 
                                 || enrollment.CMONurseID == workerID
                           let w = enrollment.EconomicSupporterWorker
                           select new
                                   {
                                       enrollment.ClientID,
                                       enrollment.CMONurseID,
                                       enrollment.CMOSocialWorkerID,
                                       enrollment.EnrollmentDate,
                                       enrollment.DisenrollmentDate,
                                       ESFirstName = w != null ? w.FirstName : null,
                                       ESLastName = w != null ? w.LastName : null,
                                       ESPhone = w != null ? w.Phone : null
                                   };
        var filteredEnrollees = AllEnrollees
            .Where(e=> e.DisenrollmentDate == null || e.DisenrollmentDate > DateTime.Now);
        //benchmark how much it delays if you do a .ToList until here
        // ... when comparing the sql, run it on the same remote computer you are running this, 
        // so you take into account the time to transfer the data.
        filteredEnrollees = filteredEnrollees 
            .OrderBy(e=> e.DisenrollmentData) // benchmark here again
            .ThenBy(e=> BLLConnect.MemberLastName(enrollee.ClientID)); // prob. causing issues
        var result = // do what you already had, but against filteredEnrollees and benchmark
        // prob. issues with BllConnect.* and BllAspnetdb.* being called for each record / 
        // ... doesn't happen in sql side

        DB.Log = Console.Out;
        return result.CopyLinqToDataTable();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...