Câu trả lời ngắn
Tùy chọn thứ ba: 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();
Câu trả lời dài
Một mặt, (hầu hết) mọi thứ bạn có thể làm trong mã, là hiệu năng tốt hơn so với thực hiện trong các truy vấn.
Mặt khác, nhận được nhiều dữ liệu từ cơ sở dữ liệu hơn mức cần thiết sẽ là quá nhiều dữ liệu (sử dụng RAM, v.v.).
Từ quan điểm của tôi, bạn cần một cái gì đó ở giữa, và chỉ có bạn mới biết đâu sẽ là số dư, tùy thuộc vào các con số.
Tôi sẽ đề nghị chạy một số truy vấn, tùy chọn cuối cùng mà bạn đề xuất ( Query all identifiers for all permissions (5), then query the Form model using the identifiers in an IN() statement
):
- Truy vấn tất cả các định danh, cho tất cả các quyền (5 truy vấn)
- Hợp nhất tất cả các kết quả biểu mẫu trong bộ nhớ và nhận các giá trị duy nhất
array_unique($ids)
- Truy vấn mô hình biểu mẫu, sử dụng các định danh trong câu lệnh IN ().
Bạn có thể thử ba tùy chọn bạn đề xuất và theo dõi hiệu suất, sử dụng một số công cụ để chạy truy vấn nhiều lần, nhưng tôi chắc chắn 99% rằng lựa chọn cuối cùng sẽ mang lại cho bạn hiệu suất tốt nhất.
Điều này cũng có thể thay đổi rất nhiều, tùy thuộc vào cơ sở dữ liệu nào bạn đang sử dụng, nhưng nếu chúng ta đang nói về MySQL chẳng hạn; Trong một truy vấn rất lớn sẽ sử dụng nhiều tài nguyên cơ sở dữ liệu hơn, nó sẽ không chỉ tiêu tốn nhiều thời gian hơn các truy vấn đơn giản mà còn khóa bảng khỏi ghi và điều này có thể tạo ra các lỗi bế tắc (trừ khi bạn sử dụng máy chủ nô lệ).
Mặt khác, nếu số lượng biểu mẫu id rất lớn, bạn có thể có lỗi cho quá nhiều trình giữ chỗ, vì vậy bạn có thể muốn phân chia các truy vấn theo nhóm, giả sử, 500 id (điều này phụ thuộc rất nhiều, vì giới hạn có kích thước, không phải về số lượng ràng buộc) và hợp nhất các kết quả trong bộ nhớ. Ngay cả khi bạn không gặp lỗi cơ sở dữ liệu, bạn cũng có thể thấy một sự khác biệt lớn về hiệu suất (tôi vẫn đang nói về MySQL).
Thực hiện
Tôi sẽ giả định rằng đây là lược đồ cơ sở dữ liệu:
users
- id
- team_id
forms
- id
- user_id
- team_id
- group_id
permissible
- user_id
- permissible_id
- permissible_type
Vì vậy, cho phép sẽ là một mối quan hệ đa hình đã được cấu hình .
Do đó, các mối quan hệ sẽ là:
- Hình thức sở hữu:
users.id <-> form.user_id
- Đội sở hữu Mẫu:
users.team_id <-> form.team_id
- Có quyền đối với một nhóm sở hữu Biểu mẫu:
permissible.user_id <-> users.id && permissible.permissible_type = 'App\Team'
- Có quyền đối với một nhóm sở hữu Biểu mẫu:
permissible.user_id <-> users.id && permissible.permissible_type = 'App\Group'
- Có quyền đối với Biểu mẫu:
permissible.user_id <-> users.id && permissible.permissible_type = 'App\From'
Đơn giản hóa phiên bản:
$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();
Phiên bản chi tiết:
// 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();
Tài nguyên được sử dụng:
Hiệu suất cơ sở dữ liệu:
- Truy vấn cơ sở dữ liệu (không bao gồm người dùng): 2 ; một để có được sự cho phép và một cái khác để có được các hình thức.
- Không tham gia !!
- Các OR tối thiểu có thể (
user_id = ? OR id IN (?..) OR team_id IN (?...) OR group_id IN (?...)
.
PHP, trong bộ nhớ, hiệu suất:
- foreach lặp vòng cho phép với một công tắc bên trong.
array_values(array_unique())
để tránh lặp lại ids.
- Trong bộ nhớ, 3 mảng của id (
$teamIds
, $groupIds
,$formIds
)
- Trong bộ nhớ, bộ sưu tập quyền hùng biện có liên quan (điều này có thể được tối ưu hóa, nếu cần).
Ưu và nhược điểm
PROS:
- Thời gian : Tổng số lần của các truy vấn đơn nhỏ hơn thời gian của một truy vấn lớn với các phép nối và OR.
- Tài nguyên DB : Tài nguyên MySQL được sử dụng bởi một truy vấn có liên kết và hoặc câu lệnh, lớn hơn tài nguyên được sử dụng bởi tổng các truy vấn riêng biệt của nó.
- Tiền : Ít tài nguyên cơ sở dữ liệu (bộ xử lý, RAM, đọc đĩa, v.v.), đắt hơn tài nguyên PHP.
- Khóa : Trong trường hợp bạn không truy vấn máy chủ nô lệ chỉ đọc, các truy vấn của bạn sẽ tạo ra ít hàng đọc khóa hơn (khóa đọc được chia sẻ trong MySQL, vì vậy nó sẽ không khóa đọc khác, nhưng nó sẽ chặn bất kỳ ghi nào).
- Khả năng mở rộng : Cách tiếp cận này cho phép bạn thực hiện nhiều tối ưu hóa hiệu suất hơn, chẳng hạn như truy vấn các truy vấn.
Nhược điểm:
- Tài nguyên mã : Thực hiện tính toán trong mã, thay vì trong cơ sở dữ liệu, rõ ràng sẽ tiêu thụ nhiều tài nguyên hơn trong trường hợp mã, nhưng đặc biệt là trong RAM, lưu trữ thông tin ở giữa. Trong trường hợp của chúng tôi, đây sẽ chỉ là một mảng id, không thực sự là một vấn đề.
- Bảo trì : Nếu bạn sử dụng các thuộc tính và phương thức của Laravel và bạn thực hiện bất kỳ thay đổi nào trong cơ sở dữ liệu, việc cập nhật mã sẽ dễ dàng hơn so với khi bạn thực hiện nhiều truy vấn và xử lý rõ ràng hơn.
- Quá mức cần thiết? : Trong một số trường hợp, nếu dữ liệu không lớn, việc tối ưu hóa hiệu suất có thể là quá mức cần thiết.
Làm thế nào để đo lường hiệu suất
Một số manh mối về cách đo hiệu suất?
- Nhật ký truy vấn chậm
- BẢNG PHÂN TÍCH
- HIỂN THỊ BẢNG TÌNH TRẠNG THÍCH
- GIẢI THÍCH ; Định dạng đầu ra mở rộng EXPLAIN ; sử dụng giải thích ; giải thích đầu ra
- CẢNH BÁO
Một số công cụ định hình thú vị: