संक्षिप्त जवाब
तीसरा विकल्प: 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();
लंबा जवाब
एक तरफ, (लगभग) वह सब कुछ जो आप कोड में कर सकते हैं, बेहतर प्रदर्शन-वार है, जो प्रश्नों में है।
दूसरी ओर, डेटाबेस से आवश्यकता से अधिक डेटा प्राप्त करना पहले से ही बहुत अधिक डेटा होगा (रैम उपयोग और इसी तरह)।
मेरे दृष्टिकोण से, आपको बीच में कुछ चाहिए, और केवल आपको पता होगा कि संख्याओं के आधार पर शेष राशि कहां होगी।
मैं कई प्रश्नों को चलाने का सुझाव दूंगा, जो अंतिम विकल्प आपने प्रस्तावित किया है ( Query all identifiers for all permissions (5), then query the Form model using the identifiers in an IN() statement
):
- सभी अनुमतियों के लिए सभी पहचानकर्ताओं से पूछताछ करें (5 प्रश्न)
- स्मृति में सभी रूपों को मिलाएं, और अद्वितीय मूल्य प्राप्त करें
array_unique($ids)
- एक () कथन में पहचानकर्ताओं का उपयोग करके फ़ॉर्म मॉडल को छोड़ें।
आप कई बार क्वेरी को चलाने के लिए कुछ टूल का उपयोग करके आपके द्वारा प्रस्तावित तीन विकल्पों को आज़मा सकते हैं और प्रदर्शन की निगरानी कर सकते हैं, लेकिन मुझे 99% यकीन है कि अंतिम आपको सबसे अच्छा प्रदर्शन देगा।
यह बहुत कुछ बदल सकता है, इस पर निर्भर करता है कि आप किस डेटाबेस का उपयोग कर रहे हैं, लेकिन अगर हम MySQL के बारे में बात कर रहे हैं, उदाहरण के लिए; एक बहुत बड़ी क्वेरी में अधिक डेटाबेस संसाधनों का उपयोग किया जाएगा, जो न केवल सरल प्रश्नों की तुलना में अधिक समय बिताएगा, बल्कि लिखने से तालिका को लॉक करेगा, और यह गतिरोध त्रुटियों का उत्पादन कर सकता है (जब तक कि आप एक दास सर्वर का उपयोग नहीं करते हैं)।
दूसरी तरफ, यदि फॉर्म आईडी की संख्या बहुत बड़ी है, तो आपके पास बहुत अधिक प्लेसहोल्डर्स के लिए त्रुटियां हो सकती हैं, इसलिए आप समूहों के प्रश्नों को चुन सकते हैं, मान लीजिए कि 500 आईडी (यह बहुत कुछ निर्भर करता है, सीमा के रूप में) आकार में है, बाइंडिंग की संख्या में नहीं है), और परिणाम को स्मृति में मर्ज करें। यहां तक कि अगर आपको डेटाबेस त्रुटि नहीं मिलती है, तो भी आपको प्रदर्शन में बड़ा अंतर दिखाई दे सकता है (मैं अभी भी MySQL के बारे में बात कर रहा हूं)।
कार्यान्वयन
मैं मानूंगा कि यह डेटाबेस योजना है:
users
- id
- team_id
forms
- id
- user_id
- team_id
- group_id
permissible
- user_id
- permissible_id
- permissible_type
तो अनुमेय पहले से ही कॉन्फ़िगर पॉलीमोर्फिक संबंध होगा ।
इसलिए, संबंध होंगे:
- मालिक का रूप:
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 ; एक को अनुमेय और दूसरे को रूपों को प्राप्त करना।
- कोई जुड़ता नहीं !!
- संभव न्यूनतम ओ आर (
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 संसाधन जो किसी क्वेरी से जुड़ने और या कथन के लिए उपयोग किया जाता है, उसके अलग-अलग प्रश्नों के योग से उपयोग किए जाने से बड़ा होता है।
- धन : कम डेटाबेस संसाधन (प्रोसेसर, रैम, डिस्क रीड, आदि), जो PHP संसाधनों से अधिक महंगे हैं।
- ताले : यदि आप किसी रीड-ओनली स्लेव सर्वर को क्वैरी नहीं कर रहे हैं, तो आपके क्वेश्चंस कम पंक्तियों को रीड रीड बना देंगे (रीड लॉक MySQL में शेयर किया गया है, इसलिए यह किसी अन्य रीड को लॉक नहीं करेगा, लेकिन यह किसी भी राइट को ब्लॉक कर देगा)।
- स्केलेबल : यह दृष्टिकोण आपको अधिक प्रदर्शन अनुकूलन करने की अनुमति देता है जैसे कि प्रश्नों को काट देना।
कान्स:
- कोड संसाधन : डेटाबेस के बजाय कोड में गणना करना, जाहिर तौर पर कोड उदाहरण में अधिक संसाधनों का उपभोग करेगा, लेकिन विशेष रूप से रैम में, मध्य सूचना को संग्रहीत करता है। हमारे मामले में, यह सिर्फ आईडी की एक सरणी होगी, जो वास्तव में एक समस्या नहीं होनी चाहिए।
- रखरखाव : यदि आप लारवेल के गुणों और विधियों का उपयोग करते हैं, और आप डेटाबेस में कोई बदलाव करते हैं, तो कोड में अपडेट करना आसान होगा, यदि आप अधिक स्पष्ट प्रश्न और प्रसंस्करण करते हैं।
- Overkilling? : कुछ मामलों में, यदि डेटा उतना बड़ा नहीं है, तो प्रदर्शन को अनुकूलित करना अधिक भारी हो सकता है।
प्रदर्शन को कैसे मापें
प्रदर्शन को मापने के तरीके के बारे में कुछ सुराग?
- धीमी क्वेरी लॉग
- विश्लेषण तालिका
- शोभित स्टेटस लाइक
- एक्सक्लूसिव ; विस्तारित प्रदर्शन आउटपुट स्वरूप ; समझाने का उपयोग करना ; आउटपुट समझाएं
- दिखाएँ चेतावनी
कुछ दिलचस्प रूपरेखा उपकरण: