Я недавно обновился до VS 2010 и играю с LINQ to Dataset. У меня есть строго типизированный набор данных для авторизации, который находится в HttpCache веб-приложения ASP.NET.
Поэтому я хотел знать, как на самом деле самый быстрый способ проверить, имеет ли пользователь право что-то делать. Вот моя модель данных и другая информация, если кому-то интересно.
Я проверил 3 способа:
- прямая база данных
- Запрос LINQ с условиями Where как «Присоединиться» - синтаксис
- Запрос LINQ с объединением - синтаксис
Это результаты с 1000 вызовами каждой функции:
1.Итерация:
- 4,2841519 сек.
- 115,7796925 сек.
- 2,024749 сек.
2.Итерация:
- 3,1954857 сек.
- 84,97047 сек.
- 1,5783397 сек.
3.Итерация:
- 2,7922143 сек.
- 97,8713267 сек.
- 1,8432163 сек.
Средний:
- База данных: 3,4239506333 сек.
- Где: 99,5404964 сек.
- Присоединяйтесь: 1,815435 сек.
Почему версия Join намного быстрее, чем синтаксис where, что делает ее бесполезной, хотя для новичка в LINQ она кажется наиболее разборчивой. Или я что-то упустил в своих запросах?
Вот запросы LINQ, я пропускаю базу данных:
Где :
Public Function hasAccessDS_Where(ByVal accessRule As String) As Boolean
Dim userID As Guid = DirectCast(Membership.GetUser.ProviderUserKey, Guid)
Dim query = From accRule In Authorization.dsAuth.aspnet_AccessRule, _
roleAccRule In Authorization.dsAuth.aspnet_RoleAccessRule, _
role In Authorization.dsAuth.aspnet_Roles, _
userRole In Authorization.dsAuth.aspnet_UsersInRoles _
Where accRule.idAccessRule = roleAccRule.fiAccessRule _
And roleAccRule.fiRole = role.RoleId _
And userRole.RoleId = role.RoleId _
And userRole.UserId = userID And accRule.RuleName.Contains(accessRule)
Select accRule.idAccessRule
Return query.Any
End Function
Присоединиться:
Public Function hasAccessDS_Join(ByVal accessRule As String) As Boolean
Dim userID As Guid = DirectCast(Membership.GetUser.ProviderUserKey, Guid)
Dim query = From accRule In Authorization.dsAuth.aspnet_AccessRule _
Join roleAccRule In Authorization.dsAuth.aspnet_RoleAccessRule _
On accRule.idAccessRule Equals roleAccRule.fiAccessRule _
Join role In Authorization.dsAuth.aspnet_Roles _
On role.RoleId Equals roleAccRule.fiRole _
Join userRole In Authorization.dsAuth.aspnet_UsersInRoles _
On userRole.RoleId Equals role.RoleId _
Where userRole.UserId = userID And accRule.RuleName.Contains(accessRule)
Select accRule.idAccessRule
Return query.Any
End Function
Заранее спасибо.
Изменить : после некоторых улучшений в обоих запросах для получения более значимых значений производительности преимущество JOIN даже во много раз больше, чем раньше:
Присоединяйтесь :
Public Overloads Shared Function hasAccessDS_Join(ByVal userID As Guid, ByVal idAccessRule As Int32) As Boolean
Dim query = From accRule In Authorization.dsAuth.aspnet_AccessRule _
Join roleAccRule In Authorization.dsAuth.aspnet_RoleAccessRule _
On accRule.idAccessRule Equals roleAccRule.fiAccessRule _
Join role In Authorization.dsAuth.aspnet_Roles _
On role.RoleId Equals roleAccRule.fiRole _
Join userRole In Authorization.dsAuth.aspnet_UsersInRoles _
On userRole.RoleId Equals role.RoleId _
Where accRule.idAccessRule = idAccessRule And userRole.UserId = userID
Select role.RoleId
Return query.Any
End Function
Где :
Public Overloads Shared Function hasAccessDS_Where(ByVal userID As Guid, ByVal idAccessRule As Int32) As Boolean
Dim query = From accRule In Authorization.dsAuth.aspnet_AccessRule, _
roleAccRule In Authorization.dsAuth.aspnet_RoleAccessRule, _
role In Authorization.dsAuth.aspnet_Roles, _
userRole In Authorization.dsAuth.aspnet_UsersInRoles _
Where accRule.idAccessRule = roleAccRule.fiAccessRule _
And roleAccRule.fiRole = role.RoleId _
And userRole.RoleId = role.RoleId _
And accRule.idAccessRule = idAccessRule And userRole.UserId = userID
Select role.RoleId
Return query.Any
End Function
Результат за 1000 звонков (на более быстром компьютере)
- Присоединяйтесь | 2. Где
1.Итерация:
- 0,0713669 сек.
- 12,7395299 сек.
2.Итерация:
- 0,0492458 сек.
- 12,3885925 сек.
3.Итерация:
- 0,0501982 сек.
- 13,3474216 сек.
Средний:
- Присоединиться: 0,0569367 сек.
- Где: 12,8251813 сек.
Присоединяйтесь в 225 раз быстрее
Заключение: избегайте WHERE для указания отношений и по возможности используйте JOIN (обязательно в LINQ to DataSet и Linq-To-Objects
в целом).
источник
Join
, зачем полагаться на оптимизатор, если вы можете написать оптимизированный код с самого начала? Это также проясняет ваши намерения. Итак, по тем же причинам, по которым вы должны предпочесть JOIN в sql .Ответы:
Ваш первый подход (SQL-запрос в БД) довольно эффективен, потому что БД знает, как выполнить соединение. Но сравнивать его с другими подходами не имеет смысла, поскольку они работают непосредственно в памяти (Linq to DataSet).
Запрос с несколькими таблицами и
Where
условием фактически выполняет декартово произведение всех таблиц, а затем фильтрует строки, удовлетворяющие условию. Это означает, чтоWhere
условие оценивается для каждой комбинации строк (n1 * n2 * n3 * n4)Join
Оператор берет строку из первых таблиц, а затем принимает только те строки , с помощью ключа согласования из второй таблицы, то только строки с ключом согласующего из третьей таблицы, и так далее. Это намного эффективнее, потому что не нужно выполнять столько операций.источник
where
-запрос каким-то образом, как dbms. Фактически, онJOIN
был даже в 225 раз быстрее, чемWHERE
(последняя редакция).Это
Join
намного быстрее, потому что метод знает, как объединить таблицы, чтобы уменьшить результат до соответствующих комбинаций. Когда вы используетеWhere
для указания отношения, он должен создать все возможные комбинации, а затем проверить условие, чтобы увидеть, какие комбинации являются релевантными.Join
Метод может создать хэш - таблицу для использования в качестве индекса Quicky пронестись две таблицы вместе, в то время какWhere
метод работает после всех комбинаций уже созданы, поэтому он не может использовать любые уловки , чтобы заранее уменьшить комбинации.источник
join
ключевого слова, поскольку во время выполнения запроса нет анализа для создания чего-либо, аналогичного плану выполнения. Вы также заметите, что объединения на основе LINQ могут поддерживать равные соединения только с одним столбцом.... on new { f1.Key1, f1.Key2 } equals new { f2.Key1, f2.Key2 }
что вам действительно нужно знать, так это sql, созданный для двух операторов. Есть несколько способов добраться до него, но самый простой - использовать LinqPad. Прямо над результатами запроса есть несколько кнопок, которые изменятся на sql. Это даст вам гораздо больше информации, чем что-либо еще.
Тем не менее, вы там поделились отличной информацией.
источник