tl;डॉ एकाधिक Include
s SQL परिणाम सेट को उड़ा दें। जल्द ही एक मेगा स्टेटमेंट चलाने के बजाय कई डेटाबेस कॉल द्वारा डेटा लोड करना सस्ता हो जाता है। Include
. का सबसे अच्छा मिश्रण खोजने का प्रयास करें और Load
बयान।
ऐसा लगता है कि शामिल करें का उपयोग करते समय एक प्रदर्शन दंड है
कि एक क्म्व्यनी है! एकाधिक Include
s SQL क्वेरी परिणाम को चौड़ाई और लंबाई दोनों में जल्दी से उड़ा देता है। ऐसा क्यों है?
Include
. का ग्रोथ फैक्टर रों
(यह हिस्सा एंटिटी फ्रेमवर्क क्लासिक, v6 और पुराने संस्करण पर लागू होता है)
मान लें कि हमारे पास है
- रूट इकाई
Root
- मूल इकाई
Root.Parent
- बाल संस्थाएं
Root.Children1
औरRoot.Children2
- एक LINQ कथन
Root.Include("Parent").Include("Children1").Include("Children2")
यह एक SQL कथन बनाता है जिसमें निम्न संरचना होती है:
SELECT *, <PseudoColumns>
FROM Root
JOIN Parent
JOIN Children1
UNION
SELECT *, <PseudoColumns>
FROM Root
JOIN Parent
JOIN Children2
ये <PseudoColumns>
जैसे भावों से मिलकर बनता है CAST(NULL AS int) AS [C2],
और वे सभी UNION
. में समान मात्रा में कॉलम रखते हैं -ed प्रश्न। पहला भाग Child2
. के लिए छद्म कॉलम जोड़ता है , दूसरा भाग Child1
. के लिए छद्म स्तंभ जोड़ता है ।
SQL परिणाम सेट के आकार के लिए इसका यही अर्थ है:
- कॉलमों की संख्या
SELECT
. में क्लॉज चार टेबल में सभी कॉलम का योग है - पंक्तियों की संख्या शामिल बाल संग्रह में रिकॉर्ड का योग है
चूंकि डेटा बिंदुओं की कुल संख्या columns * rows
. है , प्रत्येक अतिरिक्त Include
परिणाम सेट में डेटा बिंदुओं की कुल संख्या में तेजी से वृद्धि करता है। मैं Root
. लेकर इसे प्रदर्शित करता हूं फिर से, अब एक अतिरिक्त Children3
. के साथ संग्रह। यदि सभी तालिकाओं में 5 स्तंभ और 100 पंक्तियाँ हैं, तो हमें प्राप्त होता है:
एक Include
(Root
+ 1 चाइल्ड कलेक्शन):10 कॉलम * 100 पंक्तियाँ =1000 डेटा पॉइंट।
दो Include
एस (Root
+ 2 चाइल्ड कलेक्शन):15 कॉलम * 200 पंक्तियाँ =3000 डेटा पॉइंट।
तीन Include
एस (Root
+ 3 चाइल्ड कलेक्शन):20 कॉलम * 300 पंक्तियाँ =6000 डेटा पॉइंट।
12 के साथ Includes
यह 78000 डेटा अंक के बराबर होगा!
इसके विपरीत, यदि आपको 12 Includes
. के बजाय प्रत्येक तालिका के लिए अलग-अलग सभी रिकॉर्ड मिलते हैं , आपके पास 13 * 5 * 100
. है डेटा पॉइंट:6500, 10% से कम!
अब ये संख्याएं कुछ हद तक अतिरंजित हैं कि इनमें से कई डेटा बिंदु null
होंगे , इसलिए वे क्लाइंट को भेजे गए परिणाम सेट के वास्तविक आकार में अधिक योगदान नहीं देते हैं। लेकिन क्वेरी आकार और क्वेरी ऑप्टिमाइज़र के लिए कार्य निश्चित रूप से Include
की संख्या बढ़ने से नकारात्मक रूप से प्रभावित होते हैं। एस.
बैलेंस
तो Includes
. का उपयोग करना डेटाबेस कॉल और डेटा वॉल्यूम की लागत के बीच एक नाजुक संतुलन है। अंगूठे का नियम देना कठिन है, लेकिन अब तक आप कल्पना कर सकते हैं कि डेटा की मात्रा आम तौर पर अतिरिक्त कॉल की लागत को तेजी से बढ़ा देती है यदि ~3 से अधिक Includes
बाल संग्रह के लिए (लेकिन माता-पिता के लिए काफी कुछ Includes
, जो केवल परिणाम सेट को चौड़ा करता है)।
वैकल्पिक
Include
. का विकल्प अलग-अलग प्रश्नों में डेटा लोड करना है:
context.Configuration.LazyLoadingEnabled = false;
var rootId = 1;
context.Children1.Where(c => c.RootId == rootId).Load();
context.Children2.Where(c => c.RootId == rootId).Load();
return context.Roots.Find(rootId);
यह सभी आवश्यक डेटा को संदर्भ के कैश में लोड करता है। इस प्रक्रिया के दौरान, EF रिलेशनशिप फिक्सअप . को निष्पादित करता है जिससे यह नेविगेशन गुणों को स्वतः भर देता है (Root.Children
आदि) भरी हुई संस्थाओं द्वारा। अंतिम परिणाम Include
. के साथ कथन के समान है s, एक महत्वपूर्ण अंतर को छोड़कर:चाइल्ड कलेक्शन को एंटिटी स्टेट मैनेजर में लोड के रूप में चिह्नित नहीं किया जाता है, इसलिए यदि आप उन्हें एक्सेस करते हैं तो EF आलसी लोडिंग को ट्रिगर करने का प्रयास करेगा। इसलिए आलसी लोडिंग को बंद करना महत्वपूर्ण है।
वास्तव में, आपको यह पता लगाना होगा कि Include
. का कौन सा संयोजन और Load
कथन आपके लिए सर्वोत्तम कार्य करते हैं।
अन्य पहलुओं पर विचार करें
प्रत्येक Include
क्वेरी जटिलता को भी बढ़ाता है, इसलिए डेटाबेस के क्वेरी ऑप्टिमाइज़र को सर्वोत्तम क्वेरी योजना खोजने के लिए और अधिक प्रयास करने होंगे। किसी बिंदु पर यह अब सफल नहीं हो सकता है। साथ ही, जब कुछ महत्वपूर्ण अनुक्रमणिकाएं अनुपलब्ध हों (विशेष रूप से विदेशी कुंजियों पर) तो Include
को जोड़कर प्रदर्शन प्रभावित हो सकता है। s, सर्वोत्तम क्वेरी योजना के साथ भी।
इकाई फ्रेमवर्क कोर
कार्टेशियन विस्फोट
किसी कारण से, ऊपर वर्णित व्यवहार, UNIONed क्वेरीज़, को EF कोर 3 के रूप में छोड़ दिया गया था। यह अब जॉइन के साथ एक क्वेरी बनाता है। जब क्वेरी "स्टार" आकार की होती है तो इससे कार्टेशियन विस्फोट होता है (एसक्यूएल परिणाम सेट में)। मुझे इस महत्वपूर्ण परिवर्तन की घोषणा करने वाला केवल एक नोट मिल सकता है, लेकिन यह नहीं बताता कि क्यों।
क्वेरी विभाजित करें
इस कार्टेशियन विस्फोट का मुकाबला करने के लिए, एंटिटी फ्रेमवर्क कोर 5 ने विभाजित प्रश्नों की अवधारणा पेश की जो संबंधित डेटा को कई प्रश्नों में लोड करने में सक्षम बनाता है। यह एक बड़े पैमाने पर गुणा किए गए SQL परिणाम सेट के निर्माण को रोकता है। साथ ही, क्वेरी की कम जटिलता के कारण, यह कई राउंडट्रिप के साथ भी डेटा प्राप्त करने में लगने वाले समय को कम कर सकता है। हालांकि, समवर्ती अपडेट होने पर इससे असंगत डेटा हो सकता है।
एकाधिक 1:n संबंध क्वेरी रूट से बाहर हैं।