Kısa cevap
Üçüncü seçenek: Query all identifiers for all permissions (5), then query the Form model using the identifiers in an IN() statement
$teamMorphType = Relation::getMorphedModel('team');
$groupMorphType = Relation::getMorphedModel('group');
$formMorphType = Relation::getMorphedModel('form');
$permissible = [
$teamMorphType => [$user->team_id],
$groupMorphType => [],
$formMorphType => [],
];
foreach ($user->permissible as $permissible) {
switch ($permissible->permissible_type) {
case $teamMorphType:
case $groupMorphType:
case $formMorphType:
$permissible[$permissible->permissible_type][] = $permissible->permissible_id;
break;
}
}
$forms = Form::query()
->where('user_id', '=', $user->id)
->orWhereIn('id', $permissible[$fromMorphType])
->orWhereIn('team_id', $permissible[$teamMorphType])
->orWhereIn('group_id', $permissible[$groupMorphType])
->get();
Uzun cevap
Bir yandan, (neredeyse) kodda yapabileceğiniz her şey, sorgularda olduğundan daha iyi performans açısından daha iyidir.
Öte yandan, veritabanından gerekenden daha fazla veri almak zaten çok fazla veri olacaktır (RAM kullanımı vb.).
Benim açımdan, aralarında bir şeye ihtiyacınız var ve sayılara bağlı olarak dengenin nerede olacağını yalnızca siz bileceksiniz.
Birkaç sorgu çalıştırmanızı öneririm, önerilen son seçenek ( Query all identifiers for all permissions (5), then query the Form model using the identifiers in an IN() statement
):
- Tüm izinler için tüm tanımlayıcıları sorgula (5 sorgu)
- Tüm form sonuçlarını bellekte birleştirin ve benzersiz değerler elde edin
array_unique($ids)
- Bir IN () deyimindeki tanımlayıcıları kullanarak Form modelini sorgulayın.
Sorguyu birden çok kez çalıştırmak için bazı araçlar kullanarak önerdiğiniz üç seçeneği deneyebilir ve performansı izleyebilirsiniz, ancak sonuncunun size en iyi performansı vereceğinden% 99 eminim.
Bu, hangi veritabanını kullandığınıza bağlı olarak da çok değişebilir, ancak örneğin MySQL'den bahsediyorsak; Çok büyük bir sorguda sadece basit sorgulardan daha fazla zaman harcamakla kalmayacak, aynı zamanda tabloyu yazmalardan kilitleyecek daha fazla veritabanı kaynağı kullanılacaktır ve bu da (bağımlı bir sunucu kullanmıyorsanız) kilitlenme hataları üretebilir.
Diğer tarafta, form kimliği sayısı çok büyükse, çok fazla yer tutucu için hatalarınız olabilir, bu nedenle sorguları 500 id'lik gruplar halinde yığınlamak isteyebilirsiniz (diyelim ki bu sınır olarak çok şey bağlıdır) boyutunda, ciltleme sayısında değil) ve sonuçları bellekte birleştirin. Bir veritabanı hatası almasanız bile, performansta da büyük bir fark görebilirsiniz (hala MySQL'den bahsediyorum).
uygulama
Bunun veritabanı şeması olduğunu varsayacağım:
users
- id
- team_id
forms
- id
- user_id
- team_id
- group_id
permissible
- user_id
- permissible_id
- permissible_type
Dolayısıyla izin verilebilir, önceden yapılandırılmış bir polimorfik ilişki olacaktır .
Bu nedenle, ilişkiler şöyle olacaktır:
- Form sahibi:
users.id <-> form.user_id
- Takımın Formu:
users.team_id <-> form.team_id
- Form sahibi bir gruba izinleri vardır:
permissible.user_id <-> users.id && permissible.permissible_type = 'App\Team'
- Form sahibi bir ekibe izinleri vardır:
permissible.user_id <-> users.id && permissible.permissible_type = 'App\Group'
- Bir Form için izne sahip:
permissible.user_id <-> users.id && permissible.permissible_type = 'App\From'
Sürümü basitleştirin:
$teamMorphType = Relation::getMorphedModel('team');
$groupMorphType = Relation::getMorphedModel('group');
$formMorphType = Relation::getMorphedModel('form');
$permissible = [
$teamMorphType => [$user->team_id],
$groupMorphType => [],
$formMorphType => [],
];
foreach ($user->permissible as $permissible) {
switch ($permissible->permissible_type) {
case $teamMorphType:
case $groupMorphType:
case $formMorphType:
$permissible[$permissible->permissible_type][] = $permissible->permissible_id;
break;
}
}
$forms = Form::query()
->where('user_id', '=', $user->id)
->orWhereIn('id', $permissible[$fromMorphType])
->orWhereIn('team_id', $permissible[$teamMorphType])
->orWhereIn('group_id', $permissible[$groupMorphType])
->get();
Ayrıntılı sürüm:
// Owns Form
// users.id <-> forms.user_id
$userId = $user->id;
// Team owns Form
// users.team_id <-> forms.team_id
// Initialise the array with a first value.
// The permissions polymorphic relationship will have other teams ids to look at
$teamIds = [$user->team_id];
// Groups owns Form was not mention, so I assume there is not such a relation in user.
// Just initialise the array without a first value.
$groupIds = [];
// Also initialise forms for permissions:
$formIds = [];
// Has permissions to a group that owns a Form
// permissible.user_id <-> users.id && permissible.permissible_type = 'App\Team'
$teamMorphType = Relation::getMorphedModel('team');
// Has permissions to a team that owns a Form
// permissible.user_id <-> users.id && permissible.permissible_type = 'App\Group'
$groupMorphType = Relation::getMorphedModel('group');
// Has permission to a Form
// permissible.user_id <-> users.id && permissible.permissible_type = 'App\Form'
$formMorphType = Relation::getMorphedModel('form');
// Get permissions
$permissibles = $user->permissible()->whereIn(
'permissible_type',
[$teamMorphType, $groupMorphType, $formMorphType]
)->get();
// If you don't have more permissible types other than those, then you can just:
// $permissibles = $user->permissible;
// Group the ids per type
foreach ($permissibles as $permissible) {
switch ($permissible->permissible_type) {
case $teamMorphType:
$teamIds[] = $permissible->permissible_id;
break;
case $groupMorphType:
$groupIds[] = $permissible->permissible_id;
break;
case $formMorphType:
$formIds[] = $permissible->permissible_id;
break;
}
}
// In case the user and the team ids are repeated:
$teamIds = array_values(array_unique($teamIds));
// We assume that the rest of the values will not be repeated.
$forms = Form::query()
->where('user_id', '=', $userId)
->orWhereIn('id', $formIds)
->orWhereIn('team_id', $teamIds)
->orWhereIn('group_id', $groupIds)
->get();
Kullanılan kaynaklar:
Veritabanı performansı:
- Veritabanına sorgular (kullanıcı hariç): 2 ; biri müsaade edilebilir, diğeri ise formları alır.
- Katılma yok !!
- Mümkün olan minimum OR'ler (
user_id = ? OR id IN (?..) OR team_id IN (?...) OR group_id IN (?...)
.
PHP, bellekte, performansta:
- foreach içinde bir anahtar ile izin verilen döngü .
array_values(array_unique())
kimlikleri tekrarlamaktan kaçınmak için.
- Hafızada, kimlikleri 3 diziler (
$teamIds
, $groupIds
, $formIds
)
- Bellekte, ilgili izinler etkili toplama (gerekirse bu optimize edilebilir).
Lehte ve aleyhte olanlar
Artıları:
- Zaman : Tek sorguların toplamları, birleştirmeler ve OR ile büyük bir sorgu zamanından daha azdır.
- DB Kaynakları : join ve veya ifadeleri içeren bir sorgu tarafından kullanılan MySQL kaynakları, ayrı sorgularının toplamı tarafından kullanılandan daha büyüktür.
- Para : PHP kaynaklarından daha pahalı olan daha az veritabanı kaynağı (işlemci, RAM, disk okuma vb.)
- Kilitler : Salt okunur bir bağımlı sunucuyu sorgulamıyorsanız, sorgularınız daha az sayıda satır okuma kilidi yapar (okuma kilidi MySQL'de paylaşılır, bu nedenle başka bir okumayı kilitlemez, ancak herhangi bir yazmayı engeller).
- Ölçeklenebilir : Bu yaklaşım, sorguları yığınlamak gibi daha fazla performans optimizasyonu yapmanızı sağlar.
EKSİLERİ:
- Kod kaynakları : Veritabanından ziyade kodda hesaplamalar yapmak, kod örneğinde, özellikle de RAM'de orta bilgileri depolayarak daha fazla kaynak tüketecektir. Bizim durumumuzda, bu gerçekten bir sorun olmamalı sadece bir dizi kimlik olurdu.
- Bakım : Laravel'in özelliklerini ve yöntemlerini kullanırsanız ve veritabanında herhangi bir değişiklik yaparsanız, kodda güncelleme yapmak, daha açık sorgular ve işlem gerçekleştirmekten daha kolay olacaktır.
- Overkilling? : Bazı durumlarda, veriler o kadar büyük değilse, performansı optimize etmek aşırıya kaçabilir.
Performans nasıl ölçülür
Performansın nasıl ölçüleceğine dair bazı ipuçları?
- Yavaş sorgu günlükleri
- ANALİZ TABLOSU
- TABLO DURUMUNU GİBİ GÖSTER
- AÇIKLAMA ; Genişletilmiş EXPLAIN Çıktı Biçimi ; açıklama kullanarak ; çıktıyı açıkla
- UYARILARI GÖSTER
Bazı ilginç profil oluşturma araçları: