คำตอบสั้น ๆ
ตัวเลือกที่สาม: 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();
คำตอบที่ยาว
ในอีกด้านหนึ่ง (เกือบ) ทุกสิ่งที่คุณสามารถทำได้ในโค้ดนั้นดีกว่าประสิทธิภาพการทำงานมากกว่าในคิวรี
ในทางกลับกันการรับข้อมูลเพิ่มเติมจากฐานข้อมูลเกินความจำเป็นจะเป็นข้อมูลมากเกินไปแล้ว (การใช้ RAM และอื่น ๆ )
จากมุมมองของฉันคุณต้องการบางสิ่งบางอย่างในระหว่างและมีเพียงคุณเท่านั้นที่จะรู้ว่ายอดเงินจะขึ้นอยู่กับตัวเลข
ฉันขอแนะนำให้เรียกใช้หลาย ๆ คำค้นหาตัวเลือกสุดท้ายที่คุณเสนอ ( Query all identifiers for all permissions (5), then query the Form model using the identifiers in an IN() statement
):
- สอบถามตัวระบุทั้งหมดสำหรับการอนุญาตทั้งหมด (5 ข้อความค้นหา)
- ผสานผลลัพธ์ทั้งหมดในหน่วยความจำและรับค่าที่ไม่ซ้ำใคร
array_unique($ids)
- เคียวรีโมเดล Form โดยใช้ตัวระบุในคำสั่ง IN ()
คุณสามารถลองใช้สามตัวเลือกที่คุณเสนอและตรวจสอบประสิทธิภาพโดยใช้เครื่องมือบางอย่างเพื่อเรียกใช้แบบสอบถามหลายครั้ง แต่ฉันมั่นใจว่า 99% ว่าตัวสุดท้ายจะให้ประสิทธิภาพที่ดีที่สุด
สิ่งนี้อาจเปลี่ยนไปมากขึ้นอยู่กับฐานข้อมูลที่คุณใช้ แต่ถ้าเรากำลังพูดถึง MySQL เป็นต้น ในแบบสอบถามที่มีขนาดใหญ่มากจะใช้ทรัพยากรฐานข้อมูลมากขึ้นซึ่งจะไม่เพียง แต่ใช้เวลามากกว่าแบบสอบถามธรรมดา แต่ยังจะล็อกตารางจากการเขียนและสิ่งนี้สามารถสร้างข้อผิดพลาดการหยุดชะงัก (เว้นแต่คุณจะใช้เซิร์ฟเวอร์ทาส)
ในอีกด้านหนึ่งถ้าจำนวนของแบบฟอร์มรหัสมีขนาดใหญ่มากคุณสามารถมีข้อผิดพลาดสำหรับตัวยึดตำแหน่งมากเกินไปดังนั้นคุณอาจต้องการแยกกลุ่มข้อความค้นหาเป็นกลุ่มสมมติว่า 500 รหัส (ขึ้นอยู่กับข้อ จำกัด มาก มีขนาดไม่ใช่จำนวนการผูกข้อมูล) และผสานผลลัพธ์ในหน่วยความจำ แม้ว่าคุณจะไม่ได้รับข้อผิดพลาดของฐานข้อมูลคุณอาจเห็นความแตกต่างของประสิทธิภาพการทำงานที่ดีเช่นกัน (ฉันยังคงพูดถึง MySQL)
การดำเนินงาน
ฉันจะสมมติว่านี่เป็นโครงร่างฐานข้อมูล:
users
- id
- team_id
forms
- id
- user_id
- team_id
- group_id
permissible
- user_id
- permissible_id
- permissible_type
ดังนั้นได้รับอนุญาตจะมีการกำหนดค่าแล้วความสัมพันธ์ polymorphic
ดังนั้นความสัมพันธ์จะเป็น:
- แบบฟอร์มเป็นเจ้าของ:
users.id <-> form.user_id
- ทีมเป็นเจ้าของแบบฟอร์ม:
users.team_id <-> form.team_id
- มีสิทธิ์ให้กับกลุ่มที่เป็นเจ้าของแบบฟอร์ม:
permissible.user_id <-> users.id && permissible.permissible_type = 'App\Team'
- มีสิทธิ์ให้กับทีมที่เป็นเจ้าของฟอร์ม:
permissible.user_id <-> users.id && permissible.permissible_type = 'App\Group'
- ได้รับอนุญาตให้ใช้แบบฟอร์ม:
permissible.user_id <-> users.id && permissible.permissible_type = 'App\From'
ลดความซับซ้อนของเวอร์ชัน:
$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();
รุ่นโดยละเอียด:
// 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();
ทรัพยากรที่ใช้:
ประสิทธิภาพของฐานข้อมูล:
- แบบสอบถามไปยังฐานข้อมูล (ไม่รวมผู้ใช้): 2 ; หนึ่งที่จะได้รับอนุญาตและอีกหนึ่งที่จะได้รับแบบฟอร์ม
- ไม่เข้าร่วม !!
- ORs ต่ำสุดที่เป็นไปได้
user_id = ? OR id IN (?..) OR team_id IN (?...) OR group_id IN (?...)
(
PHP ในหน่วยความจำประสิทธิภาพ:
- foreachวนลูปที่อนุญาตด้วยสวิตช์ภายใน
array_values(array_unique())
เพื่อหลีกเลี่ยงรหัสซ้ำ
- ในหน่วยความจำ 3 อาร์เรย์ของรหัส (
$teamIds
, $groupIds
,$formIds
)
- ในหน่วยความจำสิทธิ์ที่เกี่ยวข้องการรวบรวมพูดจา (นี้สามารถปรับให้เหมาะสมถ้าจำเป็น)
ข้อดีและข้อเสีย
ข้อดี:
- เวลา : ผลรวมของการสืบค้นครั้งเดียวน้อยกว่าเวลาของการสืบค้นครั้งใหญ่ที่มีการรวมและ OR
- ทรัพยากร DB : ทรัพยากร MySQL ที่ใช้โดยแบบสอบถามที่มีการเข้าร่วมและหรือข้อความสั่งนั้นใหญ่กว่าการใช้โดยผลรวมของข้อความค้นหาแยกต่างหาก
- เงิน : ทรัพยากรฐานข้อมูลน้อยลง (ตัวประมวลผล RAM อ่านดิสก์ ฯลฯ ) ซึ่งมีราคาแพงกว่าทรัพยากร PHP
- ล็อค : ในกรณีที่คุณไม่ได้สืบค้นเซิร์ฟเวอร์ทาสแบบอ่านอย่างเดียวการสืบค้นของคุณจะทำการล็อคแถวที่น้อยลง (ล็อกการอ่านถูกแชร์ใน MySQL ดังนั้นมันจะไม่ล็อคการอ่านอื่น แต่จะบล็อกการเขียนใด ๆ )
- ปรับขนาดได้ : วิธีการนี้ช่วยให้คุณสามารถเพิ่มประสิทธิภาพได้มากขึ้นเช่นการสืบค้น
ข้อเสีย:
- รหัสทรัพยากร : การคำนวณในรหัสแทนที่จะอยู่ในฐานข้อมูลจะใช้ทรัพยากรมากขึ้นอย่างชัดเจนในอินสแตนซ์ของรหัส แต่โดยเฉพาะอย่างยิ่งใน RAM การจัดเก็บข้อมูลกลาง ในกรณีของเรานี่จะเป็นรหัสประจำตัวซึ่งไม่น่าจะมีปัญหาจริงๆ
- การบำรุงรักษา : หากคุณใช้คุณสมบัติและวิธีการของ Laravel และคุณทำการเปลี่ยนแปลงใด ๆ ในฐานข้อมูลจะเป็นการง่ายกว่าในการอัปเดตในโค้ดมากกว่าถ้าคุณทำการสอบถามและประมวลผลที่ชัดเจน
- Overkilling? : ในบางกรณีหากข้อมูลไม่ใหญ่มากการปรับประสิทธิภาพให้เหมาะสมอาจทำให้เกินกำลัง
วิธีการวัดประสิทธิภาพ
เบาะแสบางอย่างเกี่ยวกับวิธีการวัดประสิทธิภาพ?
- บันทึกคิวรีช้า
- วิเคราะห์ตาราง
- แสดงสถานะเหมือนตาราง
- อธิบาย ; ขยายรูปแบบเอาท์พุทขยาย ; ใช้อธิบาย ; อธิบายผลลัพธ์
- แสดงคำเตือน
เครื่องมือทำโปรไฟล์ที่น่าสนใจ: