एसक्यूएल कहाँ आईडी (आईडी 1, आईडी 2, ..., आईडीएन)


170

मुझे आईडी की एक बड़ी सूची को पुनः प्राप्त करने के लिए एक प्रश्न लिखने की आवश्यकता है।

हम कई बैकएंड (MySQL, Firebird, SQLServer, Oracle, PostgreSQL ...) का समर्थन करते हैं, इसलिए मुझे एक मानक SQL लिखने की आवश्यकता है।

आईडी सेट का आकार बड़ा हो सकता है, क्वेरी प्रोग्रामेटिक रूप से उत्पन्न होगी। तो, सबसे अच्छा तरीका क्या है?

1) IN का उपयोग करके एक क्वेरी लिखना

SELECT * FROM TABLE WHERE ID IN (id1, id2, ..., idn)

मेरा सवाल यहाँ है यदि n बहुत बड़ा है तो क्या होता है? इसके अलावा, प्रदर्शन के बारे में क्या?

2) OR का उपयोग करके एक क्वेरी लिखना

SELECT * FROM TABLE WHERE ID = id1 OR ID = id2 OR ... OR ID = idn

मुझे लगता है कि इस दृष्टिकोण की n सीमा नहीं है, लेकिन अगर n बहुत बड़ा है तो प्रदर्शन के बारे में क्या होगा?

3) एक प्रोग्रामेटिक समाधान लिखना:

  foreach (var id in myIdList)
  {
      var item = GetItemByQuery("SELECT * FROM TABLE WHERE ID = " + id);
      myObjectList.Add(item);
  }

हमें इस दृष्टिकोण के साथ कुछ समस्याओं का अनुभव हुआ जब डेटाबेस सर्वर नेटवर्क पर क्वियर होता है। आम तौर पर एक प्रश्न करना बेहतर होता है जो सभी परिणामों को पुनः प्राप्त करता है बनाम बहुत सारे छोटे प्रश्न बनाता है। शायद मैं गलत हूँ।

इस समस्या का एक सही समाधान क्या होगा?


1
विकल्प 1 में 7k ID का चयन करते हुए SQL सर्वर रिस्पांस टाइम को काफी कम करता है, जिनमें से कुछ मौजूद नहीं था। आम तौर पर क्वेरी के बारे में 1300ms लिया, यह 80ms का उपयोग करने के लिए कम कर देता है IN! मैंने आपका समाधान 1 + 3 के रूप में किया था। बस अंतिम क्वेरी एक थी, जिसे निष्पादित करने के लिए एसक्यूएल को लंबी क्वेरी स्ट्रिंग भेजा गया था।
पियोत्र कुला

जवाबों:


108

विकल्प 1 एकमात्र अच्छा समाधान है।

क्यों?

  • विकल्प 2 वही करता है लेकिन आप कॉलम नाम को बहुत बार दोहराते हैं; इसके अतिरिक्त SQL इंजन तुरंत नहीं जानता है कि आप जाँचना चाहते हैं कि क्या मूल्य एक निश्चित सूची में मानों में से एक है। हालाँकि, एक अच्छा SQL इंजन इसके साथ समान प्रदर्शन करने के लिए इसे अनुकूलित कर सकता है IN। हालांकि अभी भी पठनीयता मुद्दा है ...

  • विकल्प 3 केवल भयानक प्रदर्शन-वार है। यह हर लूप को एक क्वेरी भेजता है और छोटे प्रश्नों के साथ डेटाबेस को हथौड़े से मारता है। यह "किसी दिए गए सूची में से एक मूल्य" के लिए किसी भी अनुकूलन का उपयोग करने से भी रोकता है


2
मैं सहमत हूं लेकिन ध्यान दें कि सूची कई RDMS में सीमित है और इसलिए आपको @Ed Guiness के समाधान का उपयोग करने की आवश्यकता होगी, लेकिन यहाँ अस्थायी तालिकाएँ RDBMS के बीच भिन्न हैं। (प्रभावी रूप से जटिल समस्याओं के लिए आप सिर्फ शुद्ध मानक एसक्यूएल का उपयोग नहीं कर सकते हैं)
मिमीएमएमएम

28

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

आप इस दूसरी तालिका को काट देंगे, अपनी बड़ी संख्या में पंक्तियों को सम्मिलित करेंगे, फिर संभवत: सम्मिलित प्रदर्शन में सहायता के लिए एक सूचकांक बनाएँ। यह आपको डेटा की पुनर्प्राप्ति से इन पंक्तियों के संचय को अलग करने देगा, शायद आपको प्रदर्शन को बेहतर बनाने के लिए अधिक विकल्प देगा।

अद्यतन : यद्यपि आप एक अस्थायी तालिका का उपयोग कर सकते हैं, मेरा मतलब यह नहीं था कि आपको या यहां तक ​​कि इसका मतलब भी होना चाहिए। अस्थायी डेटा के लिए उपयोग की जाने वाली एक स्थायी तालिका यहाँ वर्णित गुणों से परे एक सामान्य समाधान है।


1
लेकिन आप उन आईडी की सूची कैसे पास करेंगे जिनकी आपको आवश्यकता है? (यह देखते हुए कि आप किसी श्रेणी या उस जैसी चीज का चयन नहीं कर सकते हैं)।
raam86

1
@ raam86: आईडी की सूची selectकिसी अन्य तालिका के विवरण का उपयोग करके प्राप्त की गई हो सकती है । सूची को उस अन्य तालिका के रूप में पास किया जाता है जिसे आप के inner joinविरुद्ध हैं।
26'18

19

एड गुनेस ने जो सुझाव दिया वह वास्तव में एक प्रदर्शन बूस्टर है, मेरे पास इस तरह से एक प्रश्न था

select * from table where id in (id1,id2.........long list)

मैंने क्या किया :

DECLARE @temp table(
            ID  int
            )
insert into @temp 
select * from dbo.fnSplitter('#idlist#')

तब मुख्य टेबुल के साथ भीतरी जुड़ गया:

select * from table inner join temp on temp.id = table.id

और प्रदर्शन में काफी सुधार हुआ।


1
नमस्ते, MSSQL से एक फ़ंक्शन fnSplitter है? क्योंकि मैं इसे खोजने में सक्षम नहीं था।
WiiMaxx

यह कोई मानक बात नहीं है। उनका मतलब यह होना चाहिए कि उन्होंने इस उद्देश्य के लिए उस फ़ंक्शन को लिखा था, या उदाहरण के लिए एक एप्लिकेशन था जो पहले से ही प्रदान किया था।
अंडरस्कोर_ड

fnSplitter रितु द्वारा बनाया गया एक फंक्शन है, आप इसे इंटरनेट / गूगल पर भी देख सकते हैं
बशर अबू शमा

9

पहला विकल्प निश्चित रूप से सबसे अच्छा विकल्प है।

SELECT * FROM TABLE WHERE ID IN (id1, id2, ..., idn)

हालाँकि यह देखते हुए कि आईडी की सूची बहुत बड़ी है , लाखों लोगों का कहना है, आपको नीचे दिए गए चंक आकारों पर विचार करना चाहिए:

  • आप Ids की सूची को निश्चित संख्या के भाग में विभाजित करें, 100 का कहना है
  • आपके सर्वर के मेमोरी साइज़ के आधार पर चंक साइज़ तय किया जाना चाहिए
  • मान लीजिए कि आपके पास 10000 Ids हैं, तो आपके पास 10000/100 = 100 हिस्सा होगा
  • एक समय में एक चंक को प्रोसेस करें जिसके परिणामस्वरूप 100 डेटाबेस कॉल सिलेक्ट होते हैं

आपको विखंडू में क्यों बांटना चाहिए?

आपको मेमोरी अतिप्रवाह अपवाद कभी नहीं मिलेगा जो आपके जैसे परिदृश्यों में बहुत सामान्य है। आपके पास बेहतर प्रदर्शन के परिणामस्वरूप डेटाबेस कॉल की संख्या अनुकूलित होगी।

इसने हमेशा मेरे लिए आकर्षण की तरह काम किया है। आशा है कि यह मेरे साथी डेवलपर्स के लिए भी काम करेगा :)


4

500 मिलियन रिकॉर्ड के साथ एक Azure SQL टेबल पर जहां () कमांड में MyTable का चयन * कर रहे हैं, जिसके परिणामस्वरूप प्रतीक्षा समय> 7min है!

ऐसा करने के बजाय तुरंत परिणाम लौटे:

select b.id, a.* from MyTable a
join (values (250000), (2500001), (2600000)) as b(id)
ON a.id = b.id

एक सम्मिलित का उपयोग करें।


3

अधिकांश डेटाबेस सिस्टम में, IN (val1, val2, …)और एक ORही योजना के लिए एक श्रृंखला को अनुकूलित किया जाता है।

तीसरा तरीका मूल्यों की सूची को एक अस्थायी तालिका में आयात करना होगा और इसमें शामिल होगा जो कि अधिकांश प्रणालियों में अधिक कुशल है, यदि बहुत सारे मूल्य हैं।

आप इस लेख को पढ़ना चाह सकते हैं:


3

नमूना 3 उन सभी में से सबसे खराब प्रदर्शन होगा क्योंकि आप बिना किसी स्पष्ट कारण के डेटाबेस को अनगिनत बार मार रहे हैं।

डेटा को एक टेम्प टेबल में लोड करना और फिर उस पर जुड़ना सबसे तेज़ गति से होगा। उसके बाद IN को ORs के समूह की तुलना में थोड़ा तेज काम करना चाहिए।


2

मुझे लगता है कि आप SqlServer का मतलब है, लेकिन Oracle पर आपके पास एक कठिन सीमा है कि आप कितने तत्वों को निर्दिष्ट कर सकते हैं: 1000।


1
यहां तक ​​कि SQL सर्वर तत्वों में ~ 40k के बाद काम करना बंद कर देता है। MSDN के अनुसार: एक इन क्लॉज में मानों की एक बहुत बड़ी संख्या (कई हजारों) शामिल करना संसाधनों का उपभोग कर सकता है और त्रुटियों को 8623 या 8632 कर सकता है। इस समस्या को हल करने के लिए, एक तालिका में आइटम को IN सूची में संग्रहीत करें।
जावेद २३'१६
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.