Saya baru saja meningkatkan ke VS 2010 dan bermain-main dengan LINQ ke Dataset. Saya memiliki set data yang diketik kuat untuk Otorisasi yang ada di HttpCache dari ASP.NET WebApplication.
Jadi saya ingin tahu apa sebenarnya cara tercepat untuk memeriksa apakah pengguna berwenang untuk melakukan sesuatu. Berikut adalah model data saya dan beberapa informasi lain jika ada yang tertarik.
Saya telah memeriksa 3 cara:
- database langsung
- Query LINQ dengan kondisi Where sebagai "Join" - Syntax
- Kueri LINQ dengan Gabung - Sintaks
Ini adalah hasil dengan 1000 panggilan di setiap fungsi:
1. Iterasi:
- 4,2841519 dtk.
- 115,7796925 dtk.
- 2.024749 dtk.
2. Iterasi:
- 3,1954857 dtk.
- 84.97047 dtk.
- 1.5783397 dtk.
3. Iterasi:
- 2,7922143 dtk.
- 97,8713267 dtk.
- 1,8432163 dtk.
Rata-rata:
- Database: 3.4239506333 dtk.
- Dimana: 99,5404964 dtk.
- Bergabung: 1,815435 dtk.
Mengapa versi Gabung jauh lebih cepat daripada sintaks di mana yang membuatnya tidak berguna meskipun sebagai pemula LINQ tampaknya yang paling terbaca. Atau apakah saya melewatkan sesuatu dalam pertanyaan saya?
Berikut adalah kueri LINQ, saya melewatkan database:
Dimana :
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
Ikuti:
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
Terima kasih sebelumnya.
Sunting : setelah beberapa perbaikan pada kedua kueri untuk mendapatkan nilai kinerja yang lebih bermakna, keuntungan dari JOIN bahkan jauh lebih besar dari sebelumnya:
Gabung :
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
Dimana :
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
Hasil untuk 1000 panggilan (di komputer yang lebih cepat)
- Gabung | 2. Dimana
1. Iterasi:
- 0,0713669 dtk.
- 12.7395299 dtk.
2. Iterasi:
- 0,0492458 dtk.
- 12,3885925 dtk.
3. Iterasi:
- 0,0501982 dtk.
- 13.3474216 dtk.
Rata-rata:
- Bergabung: 0,0569367 dtk.
- Dimana: 12,8251813 dtk.
Bergabung 225 kali lebih cepat
Kesimpulan: hindari WHERE untuk menentukan relasi dan gunakan JOIN bila memungkinkan (pasti di LINQ ke DataSet dan Linq-To-Objects
secara umum).
sumber
Join
anywhy, mengapa mengandalkan pengoptimal jika Anda dapat menulis kode opimasi dari awal? Itu juga membuat niat Anda lebih jelas. Jadi alasan yang sama mengapa Anda harus lebih memilih GABUNG di sql .Jawaban:
Pendekatan pertama Anda (kueri SQL di DB) cukup efisien karena DB tahu cara melakukan gabungan. Tetapi tidak masuk akal untuk membandingkannya dengan pendekatan lain, karena mereka bekerja secara langsung di memori (Linq ke DataSet)
Kueri dengan beberapa tabel dan
Where
kondisi benar-benar menjalankan produk kartesius dari semua tabel, lalu memfilter baris yang memenuhi ketentuan tersebut. Ini berartiWhere
kondisi dievaluasi untuk setiap kombinasi baris (n1 * n2 * n3 * n4)The
Join
Operator mengambil baris dari tabel pertama, kemudian mengambil hanya baris dengan kunci pencocokan dari tabel kedua, maka hanya baris dengan kunci yang cocok dari meja ketiga, dan seterusnya. Ini jauh lebih efisien, karena tidak perlu melakukan banyak operasisumber
where
-query dalam beberapa cara seperti dbms. SebenarnyaJOIN
itu bahkan 225 kali lebih cepat dariWHERE
(edit terakhir).Ini
Join
jauh lebih cepat, karena metode ini tahu bagaimana menggabungkan tabel untuk mengurangi hasil ke kombinasi yang relevan. Saat Anda menggunakanWhere
untuk menetapkan relasinya, ia harus membuat setiap kemungkinan kombinasi, dan kemudian menguji kondisi untuk melihat kombinasi mana yang relevan.The
Join
Metode dapat mengatur tabel hash untuk digunakan sebagai indeks untuk quicky zip dua tabel bersama-sama, sedangkanWhere
metode berjalan setelah semua kombinasi yang sudah dibuat, sehingga tidak dapat menggunakan trik apapun untuk mengurangi kombinasi terlebih dahulu.sumber
join
kata kunci, karena tidak ada analisis waktu proses kueri untuk menghasilkan sesuatu yang serupa dengan rencana eksekusi. Anda juga akan melihat bahwa gabungan berbasis LINQ hanya dapat mengakomodasi equijoin kolom tunggal.... on new { f1.Key1, f1.Key2 } equals new { f2.Key1, f2.Key2 }
yang benar-benar perlu Anda ketahui adalah sql yang dibuat untuk dua pernyataan. Ada beberapa cara untuk mendapatkannya, tetapi yang paling sederhana adalah dengan menggunakan LinqPad. Ada beberapa tombol tepat di atas hasil query yang akan berubah menjadi sql. Itu akan memberi Anda lebih banyak informasi daripada apa pun.
Informasi hebat yang Anda bagikan di sana.
sumber