क्या * अभी भी SQL Server 2012 पर एक बड़ा नहीं-नहीं का चयन करें?


41

पीछे के दिनों में, इसे प्रदर्शन के हिट होने के कारण select * from tableया न करने के लिए बड़ा नहीं माना जाता था select count(*) from table

क्या यह अभी भी SQL सर्वर के बाद के संस्करणों में मामला है (मैं 2012 का उपयोग कर रहा हूं, लेकिन मुझे लगता है कि प्रश्न 2008 - 2014 पर लागू होगा)?

संपादित करें: चूँकि लोग मुझे यहाँ थोड़ा स्लेट करते दिख रहे हैं, मैं इसे एक बेंचमार्क / अकादमिक दृष्टिकोण से देख रहा हूँ, न कि यह करने के लिए "सही" बात है कि (बेशक यह नहीं है)

जवाबों:


50

यदि आप SELECT COUNT(*) FROM TABLEकेवल एक पंक्ति (गिनती) लौटाते हैं, तो अपेक्षाकृत हल्का है, और यह उस डेटम को प्राप्त करने का तरीका है।

और SELECT *एक भौतिक नहीं-नहीं है, इसमें कानूनी और अनुमति नहीं है।

हालाँकि, समस्या SELECT *यह है कि आप बहुत अधिक डेटा आंदोलन का कारण बन सकते हैं। आप तालिका में प्रत्येक स्तंभ पर काम करते हैं। यदि आपके SELECTकेवल कुछ कॉलम शामिल हैं, तो आप अपने उत्तर को एक इंडेक्स या इंडेक्स से प्राप्त करने में सक्षम हो सकते हैं, जो I / O को कम करता है और सर्वर कैश पर प्रभाव भी पड़ता है।

तो, हाँ , यह एक सामान्य अभ्यास के रूप में अनुशंसित है क्योंकि यह आपके संसाधनों के लिए बेकार है।

SELECT *सभी स्तंभ नामों को टाइप करने का एकमात्र वास्तविक लाभ नहीं है। लेकिन SSMS से आप अपनी क्वेरी में कॉलम नाम पाने के लिए ड्रैग और ड्रॉप का उपयोग कर सकते हैं और उन्हें हटा सकते हैं जिनकी आपको आवश्यकता नहीं है।

एक सादृश्य: यदि कोई SELECT *तब उपयोग करता है जब उन्हें हर स्तंभ की आवश्यकता नहीं होती है, तो क्या वे हर पंक्ति की आवश्यकता नहीं होने पर (या कुछ अन्य सीमित खंड) के बिना भी उपयोग करेंगे ? SELECTWHERE


24

पहले से प्रदाता के जवाब के अलावा, मुझे लगता है कि यह आधुनिक ओआरएम जैसे कि एंटिटी फ्रेमवर्क के साथ काम करने पर डेवलपर्स अक्सर बहुत आलसी हैं। जब तक डीबीए से बचने के लिए अपने सबसे कठिन प्रयास करते हैं SELECT *, डेवलपर्स अक्सर सी # लिनक में शब्दार्थ के बराबर लिखते हैं:

var someVariable = db.MyTable.Where(entity => entity.FirstName == "User").ToList();

संक्षेप में, यह निम्नलिखित में परिणाम देगा:

SELECT * FROM MyTable WHERE FirstName = 'User'

एक अतिरिक्त ओवरहेड भी है जिसे पहले से कवर नहीं किया गया है। वह वह है जो प्रत्येक पंक्ति में प्रत्येक स्तंभ को संबंधित वस्तु के लिए संसाधित करने के लिए आवश्यक है। इसके अलावा, स्मृति में रखी गई प्रत्येक वस्तु के लिए, उस वस्तु को साफ किया जाना चाहिए। यदि आपने केवल उन कॉलमों का चयन किया है जिनकी आपको आवश्यकता है, तो आप आसानी से 100mb RAM से अधिक की बचत कर सकते हैं। जबकि अपने आप में एक बड़ी राशि नहीं है, कचरा संग्रह आदि का संचयी प्रभाव है जो लागत ग्राहक पक्ष है।

तो हाँ, मेरे लिए कम से कम, यह है और हमेशा एक बड़ा नहीं होगा। हमें इसे और अधिक करने की "छिपी हुई" लागतों के बारे में शिक्षित करने की भी आवश्यकता है।

परिशिष्ट

यहां केवल उसी डेटा को खींचने का एक नमूना है जिसे आपको टिप्पणियों में अनुरोध करने की आवश्यकता है:

var someVariable = db.MyTable.Where(entity => entity.FirstName == "User")
                             .Select(entity => new { entity.FirstName, entity.LastNight });

13

प्रदर्शन: SELECT * के साथ एक क्वेरी शायद कभी भी एक कवरिंग क्वेरी ( सरल बात स्पष्टीकरण , स्टैक ओवरफ्लो स्पष्टीकरण ) नहीं होगी।

भविष्य-प्रूफिंग: आपकी क्वेरी आज सभी सात कॉलमों को वापस कर सकती है, लेकिन अगर कोई अगले साल पांच कॉलम जोड़ता है तो एक साल में आपकी क्वेरी बारह कॉलम, आईओ और सीपीयू को बर्बाद कर रही है।

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

सर्वोत्तम अभ्यास : SELECT *उत्पादन कोड में कभी भी उपयोग न करें ।

उपश्रेणियों के लिए, मैं पसंद करता हूं WHERE EXISTS ( SELECT 1 FROM … )

संपादित करें : क्रेग यंग की टिप्पणी को संबोधित करने के लिए, एक उपश्रेणी में "SELECT 1" का उपयोग करना "अनुकूलन" नहीं है - ऐसा है कि मैं अपनी कक्षा के सामने खड़ा हो सकता हूं और कह सकता हूं कि "SELECT * का उपयोग न करें, कोई अपवाद नहीं!" "

एकमात्र अपवाद के बारे में मैं सोच सकता हूं कि क्लाइंट किसी तरह की पिवट-टेबल ऑपरेशन कर रहा है और उसे सभी वर्तमान और भविष्य के कॉलम की आवश्यकता होती है।

मैं CTE और व्युत्पन्न तालिकाओं से युक्त एक अपवाद को स्वीकार कर सकता हूं, हालांकि मैं निष्पादन योजनाओं को देखना चाहता हूं।

ध्यान दें कि मैं COUNT(*)इसके लिए एक अपवाद मानता हूं क्योंकि यह "*" का एक अलग वाक्यविन्यास उपयोग है।


10

SQL सर्वर 2012 में, (या 2005 से कोई भी संस्करण), SELECT *...किसी क्वेरी के शीर्ष-स्तरीय चयन कथन में केवल एक संभावित प्रदर्शन समस्या है।

इसलिए यह दृश्य (*), सबक्वेरीज में SELECT COUNT(*).., एक्जॉस्ट क्लॉस में, सीटीई में, और न ही आदि आदि में कोई समस्या नहीं है । ध्यान दें, कि यह संभवतः Oracle, और DB2 के लिए भी सही है, और शायद PostGres (निश्चित नहीं है) , लेकिन यह बहुत संभावना है कि यह अभी भी MySql के लिए बहुत सारे मामलों में एक समस्या है।

यह समझने के लिए कि (और यह अभी भी एक शीर्ष-स्तरीय चयन में समस्या क्यों हो सकती है), यह समझने में मददगार है कि यह कभी क्यों एक समस्या थी, जिसका उपयोग यह है SELECT *..कि " कॉलम के सभी वापस करें " का अर्थ है । सामान्य तौर पर यह बहुत अधिक डेटा लौटाएगा जो आप वास्तव में चाहते हैं, जिसके परिणामस्वरूप स्पष्ट रूप से बहुत अधिक आईओ, डिस्क और नेटवर्क दोनों हो सकते हैं।

जो कम स्पष्ट है वह यह भी बताता है कि SQL ऑप्टिमाइज़र का उपयोग करने वाले इंडेक्स और क्वेरी की योजना क्या है, क्योंकि यह जानता है कि यह अंततः सभी डेटा कॉलम को वापस करना होगा। यदि यह समय से पहले पता चल सकता है कि आप केवल कुछ कॉलम चाहते हैं, तो यह अक्सर अनुक्रमणिका का लाभ उठाकर अधिक कुशल क्वेरी योजनाओं का उपयोग कर सकता है जो केवल उन स्तंभों के पास हैं। सौभाग्य से समय से पहले इसे जानने का एक तरीका है, जो आपके लिए कॉलम सूची में वांछित कॉलम को स्पष्ट रूप से निर्दिष्ट करने के लिए है। लेकिन जब आप "*" का उपयोग करते हैं, तो आप इसके लिए "बस मुझे सब कुछ दे दो, मुझे पता चल जाएगा कि मुझे क्या चाहिए।"

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

तो क्या बदला? मूल रूप से, SQL ऑप्टिमाइज़र ने सफलतापूर्वक "कॉलम ऑप्टिमाइज़ेशन" नामक एक सुविधा को शामिल किया, जिसका अर्थ है कि अब वे निचले स्तर के उप-प्रश्नों में पता लगा सकते हैं यदि आप कभी भी क्वेरी के ऊपरी स्तरों में एक कॉलम का उपयोग करने जा रहे हैं।

इसका कारण यह है कि यदि आप किसी प्रश्न के निचले / भीतरी स्तरों में 'SELECT * ..' का उपयोग करते हैं तो यह कोई मायने नहीं रखता है। इसके बजाय, जो वास्तव में मायने रखता है वह यह है कि शीर्ष-स्तर के चयन की कॉलम सूची में क्या है। जब तक आप SELECT *..शीर्ष में उपयोग नहीं करते हैं , तब तक यह एक बार फिर से मान लेना चाहिए कि आप सभी कॉलम चाहते हैं, और इसलिए स्तंभ अनुकूलन को प्रभावी ढंग से नियोजित नहीं कर सकते।

(* - ध्यान दें कि व्यूज़ में एक अलग, मामूली बाध्यकारी समस्या है, *जहाँ वे हमेशा कॉलम सूचियों में परिवर्तन को पंजीकृत नहीं करते हैं जब "*" का उपयोग किया जाता है। इसे संबोधित करने के अन्य तरीके हैं और यह प्रदर्शन को प्रभावित नहीं करता है।)


5

उपयोग न करने का एक और छोटा कारण है SELECT *: यदि स्तंभों का क्रम बदल गया है, तो आपका एप्लिकेशन टूट जाएगा ... यदि आप भाग्यशाली हैं। यदि आप नहीं हैं, तो आपके पास एक सूक्ष्म बग होगा जो लंबे समय तक अनडेटेड हो सकता है। एक तालिका में फ़ील्ड्स का क्रम एक कार्यान्वयन विवरण है जिसे कभी भी अनुप्रयोगों द्वारा नहीं माना जाना चाहिए, क्योंकि यह केवल तब भी दिखाई देता है जब आप एक का उपयोग करते हैं SELECT *


4
यह अप्रासंगिक है। यदि आप अपने एप्लिकेशन कोड में कॉलम इंडेक्स द्वारा कॉलम एक्सेस कर रहे हैं, तो आपके पास एक टूटा हुआ एप्लिकेशन होना चाहिए। नाम से कॉलम एक्सेस करना हमेशा बहुत अधिक पठनीय एप्लिकेशन कोड का उत्पादन करता है और यह लगभग कभी भी प्रदर्शन की अड़चन नहीं है।
लीन रयान

3

यह शारीरिक और समस्याग्रस्त रूप से उपयोग करने की अनुमति है select * from table, हालांकि, यह एक बुरा विचार है। क्यों?

सबसे पहले, आप पाएंगे कि आप ऐसे कॉलम लौटा रहे हैं जिनकी आपको आवश्यकता नहीं है (संसाधन भारी)।

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

तीसरा, ऐसा करना वास्तव में डेवलपर के लिए कठिन बनाता है। कॉलम नाम के सभी पाने के लिए आपको कितनी बार SSMS से VS के आगे और पीछे फ्लिप करने की आवश्यकता है?

चौथा, यह आलसी प्रोग्रामिंग का संकेत है और मुझे नहीं लगता कि कोई भी डेवलपर उस प्रतिष्ठा को चाहेगा।


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

आपके दूसरे तर्क के बारे में, यह एक सामान्य गलत धारणा है - SELECT * की समस्या मेटाडेटा लुकअप नहीं है, क्योंकि यदि आप कॉलम का नाम देते हैं, तो SQL सर्वर को अभी भी उनके नामों को मान्य करना है, डेटा प्रकारों की जांच करनी है, आदि
हारून बर्ट्रेंड

@ विस्तृत चयन के साथ समस्याओं में से एक * होता है जब आप एक दृश्य में डालते हैं। यदि आप अंतर्निहित स्कीमा को बदलते हैं, तो दृश्य भ्रमित हो सकता है - इसमें अब तालिका की तुलना में तालिका के स्कीमा (अपना) की एक अलग अवधारणा है। मैं यहां इस बारे में बात करता हूं
हारून बर्ट्रेंड

3

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

यह कहने के बाद कि, मुझे एक समस्या है जब Select *एक EXISTSखंड का हिस्सा है , क्योंकि यह सब कार्यक्रम में वापस आने वाला है, चयन की सफलता या विफलता का संकेत करने वाला एक बूलियन है। अन्य लोग इस रुख से असहमत हो सकते हैं और मैं उस पर उनकी राय का सम्मान करता हूं। यह कोड की Select *तुलना में 'सेलेक्ट 1' को कोड करने के लिए कोड की तुलना में थोड़ा कम कुशल हो सकता है EXISTS, लेकिन मुझे नहीं लगता कि डेटा भ्रष्टाचार का कोई खतरा है, किसी भी तरह से।


वास्तव में, हां, मेरा मतलब था EXISTS क्लॉज का संदर्भ देना। मेरी गलती।
मार्क रॉस

2

बहुत सारे उत्तर select *गलत क्यों हैं, इसलिए जब मुझे लगता है कि यह सही है या कम से कम ठीक है तो मैं कवर करूंगा।

1) एक उदाहरण में, क्वेरी के चयनित भाग की सामग्री को नजरअंदाज कर दिया जाता है, इसलिए आप लिख भी सकते हैं SELECT 1/0और यह त्रुटि नहीं करेगा। EXISTSबस यह सत्यापित करता है कि कुछ डेटा वापस आएगा और उसी के आधार पर एक बूलियन लौटाएगा।

IF EXISTS(
    SELECT * FROM Table WHERE X=@Y
)

2) यह एक आग्नेयास्त्र शुरू कर सकता है, लेकिन मुझे select *अपने इतिहास तालिका ट्रिगर में उपयोग करना पसंद है। द्वारा select *, यह मुख्य टेबल को हिस्ट्री टेबल के साथ कॉलम को जोड़े बिना एक नया कॉलम प्राप्त करने से रोकता है और साथ ही मुख्य तालिका में सम्मिलित / अद्यतन / हटाए जाने पर तुरंत त्रुटि करता है। यह कई बार रोका गया है जहां डेवलपर्स कॉलम जोड़ रहे हैं और इसे इतिहास तालिका में जोड़ना भूल गए हैं।


3
मैं अभी भी पसंद SELECT 1करता हूं क्योंकि यह सबसे स्पष्ट रूप से आपके इरादे के भविष्य के कोड अनुचर को सूचित करता है। यह एक आवश्यकता नहीं है , लेकिन अगर मैं ... WHERE EXISTS (SELECT 1 ...)इसे स्पष्ट रूप से देखता हूं तो खुद को एक सत्य परीक्षा के रूप में घोषित करता है।
स्वैसेक करें

1
@zlatanMany लोग SELECT 1एक मिथक के आधार पर उपयोग करते हैं कि प्रदर्शन से बेहतर होगा SELECT *। हालांकि, दोनों विकल्प पूरी तरह से स्वीकार्य हैं। जिस तरह से ऑप्टिमाइज़र EXISTS को हैंडल करता है, उसके कारण प्रदर्शन में कोई अंतर नहीं है। शब्द "EXISTS" के कारण पठनीयता में कोई अंतर नहीं है जो स्पष्ट रूप से एक सत्य परीक्षण की घोषणा करता है।
मोहभंग

बिंदु # 2 पर, मैं आपके तर्क को समझता हूं, लेकिन अभी भी जोखिम हैं। मुझे 'आपके लिए एक परिदृश्य पेंट करें' ... डेवलपर Column8इतिहास तालिका को भूलते हुए मुख्य तालिका में जोड़ता है। डेवलपर ने कॉलम 8 को साकार कोड का एक गुच्छा लिखा है। फिर वह Column9मुख्य तालिका में जोड़ता है; यह समय इतिहास में जोड़ने का भी है। बाद में जब वह परीक्षण करता है तो उसे पता चलता है कि वह Column9इतिहास में जोड़ना भूल गया (आपकी त्रुटि का पता लगाने की तकनीक के लिए धन्यवाद), और तुरंत इसे जोड़ता है। अब ट्रिगर काम करने लगता है, लेकिन इतिहास में कॉलम 8 और 9 में डेटा मिलाया जाता है। : S
मोहभंग

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

@CraigYoung यह एक संभावना है। लेकिन मैं किसी को गला घोंटूंगा अगर उन्होंने ऐसा किया। यह एक ऐसी गलती नहीं है जिसे आप आसानी से कर सकते हैं
UnhandledExcepSean
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.