SQL सर्वर त्रुटि 8632 WHERE क्लॉज में 100,000 से अधिक प्रविष्टियों के कारण


16

मेरी समस्या (या कम से कम त्रुटि संदेश) आंतरिक संसाधनों से बाहर भाग गए क्वेरी प्रोसेसर के समान है - अत्यंत लंबी एसक्यूएल क्वेरी

मेरा ग्राहक एक SQL चयन-क्वेरी के साथ काम कर रहा है, जिसमें बिल्कुल 100,000 प्रविष्टियों के साथ एक क्लॉज है।

त्रुटि 8632 और त्रुटि संदेश के साथ क्वेरी विफल हो रही है

आंतरिक त्रुटि: एक अभिव्यक्ति सेवाओं की सीमा पूरी हो चुकी है। कृपया अपनी क्वेरी में संभावित जटिल अभिव्यक्तियों की तलाश करें, और उन्हें सरल बनाने का प्रयास करें।)

मुझे यह बहुत अजीब लगता है कि यह त्रुटि संदेश बिल्कुल 100,000 प्रविष्टियों पर फेंका गया है, इसलिए मुझे आश्चर्य है कि क्या यह एक विन्यास योग्य मूल्य है। क्या यह मामला है और मामले में हाँ, मैं इस मूल्य को उच्चतर कैसे बढ़ा सकता हूं?

पर MSDN , वहाँ प्रस्ताव क्वेरी फिर से पुनर्लेखन के लिए है, लेकिन मैं इस से बचने के लिए चाहते हैं।

इस बीच मुझे पता चला कि जिन प्रविष्टियों के बारे में मैं बात कर रहा हूँ उनमें प्राकृतिक संख्याएँ हैं, उनमें से कुछ क्रमबद्ध हैं (कुछ ऐसा है (1,2,3,6,7,8,9,10,12) 13,15,16,17,18,19,20)।

यह एसक्यूएल बनाता है जहाँ-क्लॉज कुछ इस तरह है:

where entry in (1,2,3,6,7,8,9,10,12,13,15,16,17,18,19,20)

मैं इस में बदल सकता है:

where (entry between 1 and 3) OR
      (entry between 6 and 10) OR
      (entry between 12 and 13) OR
      (entry between 15 and 20)

क्या इसे छोटा किया जा सकता है:

where entry in (1,...,3,6,...,10,12,13,15,...,20)

... या ऐसा ही कुछ? (मुझे पता है कि यह एक लंबा शॉट है, लेकिन यह सॉफ़्टवेयर अपडेट को आसान और अधिक पठनीय बना देगा)

आपकी जानकारी के लिए: जहां-जहां खंड में डेटा एक गणना का परिणाम है, दूसरी तालिका पर किया जाता है: पहले उस तालिका की प्रविष्टियां पढ़ी जाती हैं और शुरुआत में फ़िल्टर की जाती हैं, फिर कुछ अतिरिक्त प्रसंस्करण किया जाता है (जिसका उपयोग करना असंभव है एसक्यूएल), उस अतिरिक्त प्रसंस्करण का परिणाम अधिक फ़िल्टरिंग है और उस के परिणाम का उपयोग जहां-जहां-खंड में किया जाता है। चूंकि एसक्यूएल में पूरा फ़िल्टरिंग लिखना असंभव था, इसलिए उल्लिखित विधि का उपयोग किया गया है। जाहिर है कि जहां-जहां प्रत्येक खंड में क्लॉज की सामग्री बदल सकती है, इसलिए एक गतिशील समाधान की आवश्यकता है।


7
आपके संपादन के जवाब में: नहीं, WHERE INउस प्रकार के श्रेणी सिंटैक्स का समर्थन नहीं करता है। इसके अलावा, यह WHERE () OR () OR ()नहीं होना चाहिए । लेकिन ब्रेंट के सुझाव का उपयोग करने के लिए, आपको वास्तव में पूरी क्वेरी को बदलने की ज़रूरत नहीं है, आप बस कर सकते हैं WHERE IN (SELECT myID FROM #biglist)। और #biglistया तो एक वास्तविक (स्थायी) टेबल हो सकता है, या एक अस्थायी तालिका जो आप मक्खी पर बनाते हैं।
ब्रैडक

कृपया कृपया पूरी क्वेरी पोस्ट करें और जो आप बाह्य रूप से गणना कर रहे हैं, यह संभवतः वास्तव में कुछ है जो आप SQL में पूरी तरह से कर सकते हैं। यदि आप गोपनीयता या जो भी संबंधित हैं, तो फ़ील्ड नामों का नाम बदलें।
माइक

जवाबों:


67

100,000 से अधिक मानों की खोज करने के लिए, उन्हें एक अस्थायी तालिका में रखें, प्रति पंक्ति एक पंक्ति जिसे आप खोज रहे हैं। फिर, फ़िल्टर करने के लिए उस अस्थायी तालिका में अपनी क्वेरी से जुड़ें।

100,000 से अधिक मूल्यों के साथ कुछ एक पैरामीटर नहीं है - यह एक तालिका है। सीमा बढ़ाने के बारे में सोचने के बजाय, Swart के दस प्रतिशत नियम पर विचार करें : यदि आप SQL सर्वर सीमा के 10% के करीब पहुंच रहे हैं, तो आप शायद एक बुरा समय लेने वाले हैं।


1
टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
पॉल व्हाइट को फिर से बहाल मोनिका

10

यदि आप वैसे भी ऐप बदलने जा रहे हैं, तो या तो विचार करें

(ए) मूल्यों के पूरे सेट के लिए एक टीवीपी का उपयोग करना - आप एक DataTableसी # बनायेंगे और इसका उपयोग करके एक संग्रहीत प्रक्रिया में पास StructuredTypeकरेंगे, जैसा कि मैं यहां प्रदर्शित करता हूं । (उम्मीद है कि 100,000 प्रविष्टियां सामान्य नहीं हैं, क्योंकि स्केलेबिलिटी एक मुद्दा हो सकती है, इससे कोई फर्क नहीं पड़ता कि आप किस दृष्टिकोण का उपयोग करते हैं।)

CREATE TYPE dbo.optionA AS TABLE(value int PRIMARY KEY);
GO

CREATE PROCEDURE dbo.procedure_optionA
  @t dbo.optionA READONLY
AS
BEGIN
  SET NOCOUNT ON;
  SELECT <cols> FROM dbo.<table> AS t
    INNER JOIN @t AS tvp
    ON t.entry = tvp.value;
END
GO

या

(बी) रेंज के ऊपरी और निचले सीमा में पारित करने के लिए एक टीवीपी का उपयोग करना, और थोड़ा अलग सम्मिलित लिखना (धन्यवाद @ypercube)।

  CREATE TYPE dbo.optionB AS TABLE
  (
    LowerBound int,
    UpperBound int,
    PRIMARY KEY (LowerBound, UpperBound)
  );
  GO

  CREATE PROCEDURE dbo.procedure_optionB
    @t dbo.OptionB READONLY
  AS
  BEGIN
    SET NOCOUNT ON;
    SELECT <cols> FROM dbo.<table> AS t
      INNER JOIN @t AS tvp
      ON  t.entry >= tvp.LowerBound 
      AND t.entry <= tvp.UpperBound;
  END
  GO

6

नहीं, यह विन्यास योग्य नहीं है और आप इसे उच्चतर तक नहीं बढ़ा सकते।

आपके द्वारा उल्लेखित MSDN लेख और अन्य लेखों में सुझाए गए वर्कअराउंड हैं। मैंने यहां दो का उल्लेख किया है लेकिन आप और अधिक खोज सकते हैं।


4

बस मेरी 2 query क्वेरी की स्थिति को कम करने के बारे में: -

यदि आप पहले से सभी संभावित मूल्यों को निर्धारित करने में सक्षम हैं entry, तो यदि आप अपनी क्वेरी के पूरक लेते हैं तो क्या यह संभव होगा?

इससे पहले

where entry in (1,2,3,6,7,8,9,10,12,13,15,16,17,18,19,20)

उपरांत

where entry not in (4,5,11,14)

0

यह पता लगाना मुश्किल है कि आप वास्तव में क्वेरी देखने में सक्षम होने के बिना क्या हासिल करने की कोशिश कर रहे हैं, लेकिन यहां हम यह मानते हैं कि आपकी क्वेरी को केवल दो तालिकाओं की जरूरत है, एक डेटा के साथ, एक वह मान जिसके साथ आप बचना चाहते हैं:

  • where entry in (<list of 100.000 values>)दक्षता और रखरखाव के दृष्टिकोण से, अपमानजनक रूप से भयानक है, का उपयोग करना ।
  • का उपयोग करना where entry in (select whatever from table)मुश्किल से पहले के रूप में अत्याचार के रूप में भयानक है। फिर भी, दोनों तालिकाओं के आधार पर idiosyncrasy और SQL इंजन, यह कॉर्निया कैंसर के बावजूद ठीक प्रदर्शन कर सकता है। (Oracle में ठीक हो सकता है, MySQL में कभी नहीं होगा, MSSQL के बारे में याद नहीं कर सकता)।
  • इसे प्राप्त करने के लिए PLSQL का उपयोग करना केवल भयावह है।
  • मेरी राय में (क्वेरी को बिल्कुल भी जाने बिना), आपको क्वेरी को इस प्रकार लिखना चाहिए:

    • यदि वे 100.000 मान हमेशा समान होते हैं, तो बाकी क्वेरी पर निर्भर नहीं होते हैं, तो आपको उन मानों को एक तालिका (table_fixed_values) पर अपलोड करना चाहिए, और उपयोग करना चाहिए

      SELECT * -- whatever you might need
      FROM
         table_a A
         LEFT JOIN table_fixed_values ON A.entry=B.entry
      WHERE B.entry IS NOT NULL
    • यदि वे 100.000 मान समान नहीं हैं, तो उन 100.000 मूल्यों को लेने के लिए किसी प्रकार का तर्क होना चाहिए, तर्क जो आपको ONपिछली क्वेरी के अंत में एम्बेड करना चाहिए ।


3
LEFT JOIN table_fixed_values ON A.entry=B.entry WHERE B.entry IS NOT NULLसमतुल्य, सरल और पढ़ने में आसान क्यों INNER JOIN table_fixed_values ON A.entry=B.entry?
ypercube y

@ ypercube y पूरी तरह से सही है, INNER JOIN अधिक मायने रखता है।
glezo
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.