2016-09-02 7 views
11

भारी बहु थ्रेडेड परिदृश्य में, मुझे एक विशेष ईएफ क्वेरी के साथ समस्याएं हैं।ईएफ बनाम एसक्यूएल

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) नमूना पता चलता है कि धागे के लिए सभी निम्न विधि में अपना समय बिताते हैं लगते हैं:

dotTrace sample

क्या मैं नहीं छूटा है है या हम कुछ मारा था ADO.NET/एसक्यूएल सर्वर cornercase?


अधिक संदर्भ

कोड इस क्वेरी चलाने एक Hangfire काम है। परीक्षण के उद्देश्य के लिए, एक स्क्रिप्ट कई कामों को कतारबद्ध करती है और 40 धागे तक नौकरी को संसाधित करते रहते हैं। प्रत्येक नौकरी एक अलग DbContext उदाहरण का उपयोग करती है और इसका वास्तव में बहुत उपयोग नहीं किया जा रहा है। समस्याग्रस्त क्वेरी से पहले और बाद में कुछ और प्रश्न हैं और वे निष्पादित करने के लिए अपेक्षित समय लेते हैं।

हम इसी तरह के उद्देश्यों के लिए कई अलग हैंगफायर नौकरियों का उपयोग कर रहे हैं और वे अपेक्षा के अनुसार व्यवहार करते हैं। इस के साथ, को छोड़कर जब यह धीमी गति से धीमी हो जाती है (ठीक उसी नौकरियों के)। साथ ही, इस विशेष क्वेरी पर SQL पर स्विच करने से समस्या ठीक हो जाती है।

उपरोक्त प्रोफाइलिंग स्नैपशॉट प्रतिनिधि है, सभी थ्रेड इस विशेष विधि कॉल पर धीमा हो जाते हैं और अपने अधिकांश समय पर खर्च करते हैं।


अद्यतन

मैं वर्तमान में विवेक और त्रुटियों के लिए उन चेकों का एक बहुत फिर से चल रहा हूँ। आसान पुनरुत्पादन का अर्थ है कि यह अभी भी एक दूरस्थ मशीन पर है जिसके लिए मैं डीबगिंग के लिए वीएस का उपयोग नहीं कर सकता।

चेक में से एक ने दिखाया कि मुफ्त सीपीयू के बारे में मेरा पिछला बयान गलत था, सीपीयू पूरी तरह से अधिभारित नहीं था लेकिन लंबे समय तक चलने वाली नौकरियों की पूरी अवधि के लिए कई कोर वास्तव में पूर्ण क्षमता पर चल रहे थे।

सब कुछ फिर से जांचना और यहां अपडेट के साथ वापस आ जाएगा।

+0

यह विधि बस सर्वर का जवाब देने के लिए प्रतीक्षा करती है। यह गलती नहीं है। (मुझे नहीं पता कि क्या है।) – usr

+0

उस बिंदु पर जहां यह धीमा है, डीबगर को रोकें और समांतर स्टैक्स विंडो का स्क्रीनशॉट कैप्चर करें। हमें धागे क्या कर रहे हैं इसका एक नमूना चाहिए। – usr

+0

जैसा ऊपर बताया गया है, प्रोफाइलर गर्म पथ दिखाता है - सभी थ्रेड इस विधि पर धीमा हो जाते हैं। मुझे एसक्यूएल कनेक्टर या शायद घटनाओं की एक श्रृंखला में एक कोने केस पर संदेह है जो एसक्यूएल को खुद को अवरुद्ध/धीमा कर देता है (यहां तक ​​कि मुफ्त संसाधनों के साथ)। –

उत्तर

1

दोषपूर्ण प्रारंभिक धारणाएं। प्रश्न में एसक्यूएल को LINQPad में कोड चिपकाकर और इसे SQL उत्पन्न करने के द्वारा प्राप्त किया गया था।

वास्तविक डीबी के लिए एसक्यूएल प्रोफाइलर को जोड़ने के बाद, यह थोड़ा अलग एसक्यूएल बाहरी जोड़ों को शामिल करता है, जो उप-स्थानिक हैं और इसमें उचित सूचकांक नहीं है।

यह एक रहस्य है कि LINQPad ने अलग-अलग SQL उत्पन्न क्यों किया, भले ही यह उसी EntityFramework.dll का उपयोग कर रहा हो, लेकिन मूल समस्या हल हो गई है और यह सब बनी हुई है क्वेरी को अनुकूलित करना।

शामिल सभी के लिए बहुत धन्यवाद।

1

आप नीचे दिखाए अनुसार कर सकते हैं की कोशिश और देखें कि क्या वहाँ किसी भी प्रदर्शन में सुधार या नहीं है ...

Context.MyEntity.AsNoTracking() 
    .Any(se => se.SameEntity.Field == someValue   
    && se.AnotherEntity.Field == anotherValue 
    && se.SimpleField == simpleValue 
    ); 
+0

'' कोई भी() '' '' iQueryable'' पर एक विस्तार विधि है, जबकि '' IQueryable'' पर एक एक्सटेंशन विधि है ... –

+0

मैंने जवाब अपडेट किया है। कृपया इसे अभी देखें। – Sampath

+0

AsNoTracking() पहले कोशिश की गई थी और इसका कोई प्रभाव नहीं पड़ा। असल में, एसक्यूएल क्वेरी केवल एक नंबर लौटाती है, इसलिए ट्रैकिंग जिम्मेदार नहीं होनी चाहिए (वैसे भी उचित दुनिया में)। –

1

चेक, अगर आप एक पाश में संदर्भ पुन: उपयोग कर रहे हैं। ऐसा करने से आपके प्रदर्शन परीक्षण के दौरान कई वस्तुएं पैदा हो सकती हैं और कचरा कलेक्टर को बहुत काम करना पड़ सकता है।

संबंधित मुद्दे