भारी बहु थ्रेडेड परिदृश्य में, मुझे एक विशेष ईएफ क्वेरी के साथ समस्याएं हैं।ईएफ बनाम एसक्यूएल
Context.MyEntity
.Any(se => se.SameEntity.Field == someValue
&& se.AnotherEntity.Field == anotherValue
&& se.SimpleField == simpleValue
// few more simple predicates with fields on the main entity
);
यह एक बहुत ही उचित SQL क्वेरी में संकलित:
SELECT
CASE WHEN (EXISTS (SELECT
1 AS [C1]
FROM (SELECT [Extent1].[Field1] AS [Field1]
FROM [dbo].[MyEntity] AS [Extent1]
INNER JOIN [dbo].[SameEntity] AS [Extent2] ON [Extent1].[SameEntity_Id] = [Extent2].[Id]
WHERE (N'123' = [Extent2].[SimpleField]) AND (123 = [Extent1].[AnotherEntity_Id]) AND -- further simple predicates here --) AS [Filter1]
INNER JOIN [dbo].[AnotherEntity] AS [Extent3] ON [Filter1].[AnotherEntity_Id1] = [Extent3].[Id]
WHERE N'123' = [Extent3].[SimpleField]
)) THEN cast(1 as bit) ELSE cast(0 as bit) END AS [C1]
FROM (SELECT 1 AS X) AS [SingleRowTable1]
क्वेरी, सामान्य रूप में, इष्टतम क्वेरी योजना है, के दसियों में सही सूचकांक और रिटर्न का उपयोग करता है यह आम तौर पर सस्ता और तेज है मिलीसेकंड जो पूरी तरह से स्वीकार्य है।
हालांकि, जब धागे की एक महत्वपूर्ण संख्या (< = 40) इस क्वेरी को क्रियान्वित करने शुरू होता है, उस पर प्रदर्शन सेकंड के दसियों के लिए चला जाता है।
डेटाबेस में कोई ताले नहीं हैं, इन तालिकाओं में कोई प्रश्न डेटा नहीं लिख रहा है और यह किसी भी अन्य परिचालन से व्यावहारिक रूप से अलग डेटाबेस के साथ बहुत अच्छी तरह से पुन: उत्पन्न करता है। डीबी एक ही भौतिक मशीन पर रहता है और
मशीन किसी भी बिंदु पर अधिभारित नहीं होती है, यानी बहुत सारे अतिरिक्त सीपीयू, मेमोरी और अन्य संसाधन हैं
सीपीयू इस ऑपरेशन द्वारा अधिभारित है।
अब क्या वास्तव में विचित्र है कि जब मैं कॉपी-पेस्ट किया एसक्यूएल (पैरामीटर भी उपयोग करते हुए) के साथ Context.Database.ExecuteSqlCommand()
साथ एफई Any()
कॉल की जगह, समस्या जादुई गायब हो जाता है है। दोबारा, यह बहुत विश्वसनीय रूप से पुन: उत्पन्न करता है - Any()
प्रतिलिपि बनाकर कॉपी-पेस्ट एसक्यूएल के साथ कॉल परिमाण के 2-3 ऑर्डर द्वारा प्रदर्शन को बढ़ाता है।
एक संलग्न प्रोफाइलर (dotTrace) नमूना पता चलता है कि धागे के लिए सभी निम्न विधि में अपना समय बिताते हैं लगते हैं:
क्या मैं नहीं छूटा है है या हम कुछ मारा था ADO.NET/एसक्यूएल सर्वर cornercase?
अधिक संदर्भ
कोड इस क्वेरी चलाने एक Hangfire काम है। परीक्षण के उद्देश्य के लिए, एक स्क्रिप्ट कई कामों को कतारबद्ध करती है और 40 धागे तक नौकरी को संसाधित करते रहते हैं। प्रत्येक नौकरी एक अलग DbContext
उदाहरण का उपयोग करती है और इसका वास्तव में बहुत उपयोग नहीं किया जा रहा है। समस्याग्रस्त क्वेरी से पहले और बाद में कुछ और प्रश्न हैं और वे निष्पादित करने के लिए अपेक्षित समय लेते हैं।
हम इसी तरह के उद्देश्यों के लिए कई अलग हैंगफायर नौकरियों का उपयोग कर रहे हैं और वे अपेक्षा के अनुसार व्यवहार करते हैं। इस के साथ, को छोड़कर जब यह धीमी गति से धीमी हो जाती है (ठीक उसी नौकरियों के)। साथ ही, इस विशेष क्वेरी पर SQL पर स्विच करने से समस्या ठीक हो जाती है।
उपरोक्त प्रोफाइलिंग स्नैपशॉट प्रतिनिधि है, सभी थ्रेड इस विशेष विधि कॉल पर धीमा हो जाते हैं और अपने अधिकांश समय पर खर्च करते हैं।
अद्यतन
मैं वर्तमान में विवेक और त्रुटियों के लिए उन चेकों का एक बहुत फिर से चल रहा हूँ। आसान पुनरुत्पादन का अर्थ है कि यह अभी भी एक दूरस्थ मशीन पर है जिसके लिए मैं डीबगिंग के लिए वीएस का उपयोग नहीं कर सकता।
चेक में से एक ने दिखाया कि मुफ्त सीपीयू के बारे में मेरा पिछला बयान गलत था, सीपीयू पूरी तरह से अधिभारित नहीं था लेकिन लंबे समय तक चलने वाली नौकरियों की पूरी अवधि के लिए कई कोर वास्तव में पूर्ण क्षमता पर चल रहे थे।
सब कुछ फिर से जांचना और यहां अपडेट के साथ वापस आ जाएगा।
यह विधि बस सर्वर का जवाब देने के लिए प्रतीक्षा करती है। यह गलती नहीं है। (मुझे नहीं पता कि क्या है।) – usr
उस बिंदु पर जहां यह धीमा है, डीबगर को रोकें और समांतर स्टैक्स विंडो का स्क्रीनशॉट कैप्चर करें। हमें धागे क्या कर रहे हैं इसका एक नमूना चाहिए। – usr
जैसा ऊपर बताया गया है, प्रोफाइलर गर्म पथ दिखाता है - सभी थ्रेड इस विधि पर धीमा हो जाते हैं। मुझे एसक्यूएल कनेक्टर या शायद घटनाओं की एक श्रृंखला में एक कोने केस पर संदेह है जो एसक्यूएल को खुद को अवरुद्ध/धीमा कर देता है (यहां तक कि मुफ्त संसाधनों के साथ)। –