दिलचस्प पोस्ट
आईओएस 10.3 पर टेली: // स्कीम का उपयोग करते हुए एक फ़ोन नंबर डायल करने का प्रयास करते समय पूछें सीएसएस में डेटा विशेषता के आधार पर तत्व चुनें तृतीय पक्ष वेब सेवा के माध्यम से क्लाइंट आईपी पता प्राप्त करें Android अंतहीन सूची एंटरप्राइज़ आईओएस एप्लिकेशन इंस्टॉल करते समय "अविश्वस्त ऐप डेवलपर" संदेश क्या करें @, – और + मेक में नुस्खा लाइनों के उपसर्ग के रूप में करते हैं? JSON में शून्य का प्रतिनिधित्व करना Facet_wrap और तराजू = "मुक्त" के साथ व्यक्तिगत अक्ष की सीमा सेट करना ggplot2 में अगर आप विशेष रूप से उद्देश्य-सी में संपत्ति का उपयोग कर रहे हैं तो क्या ईवर्स को घोषित करने का कोई कारण है? दूसरे के ऊपर दो बटन एक के साथ एक रिलेटिव लेआउट प्रोग्रामेटिक रूप से कैसे बनाऊँ? एचटीएमएल को पीडीएफ़ का उपयोग करके पीडीएफ में परिवर्तित करना? रूबी हैश की तुलना आईओएस 8 – एंटरप्राइज़ एप स्थापित नहीं कर सकता MPI_Rank सभी प्रक्रिया के लिए इसी प्रक्रिया संख्या वापस आती है एसक्यूएल परिणाम (या तो माइस्किल या पर्ल अंत पर) में रिक्त तिथियों के पैड का सबसे सीधा तरीका क्या है?

सबसे आम एसक्यूएल विरोधी पैटर्न क्या हैं?

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

Solutions Collecting From Web of "सबसे आम एसक्यूएल विरोधी पैटर्न क्या हैं?"

मैं डेटा एपरेस्ट परत में अपने यूआई-लॉजिक को मिलाकर अधिकांश प्रोग्रामर्स की प्रवृत्ति से लगातार निराश हूं:

 SELECT FirstName + ' ' + LastName as "Full Name", case UserRole when 2 then "Admin" when 1 then "Moderator" else "User" end as "User's Role", case SignedIn when 0 then "Logged in" else "Logged out" end as "User signed in?", Convert(varchar(100), LastSignOn, 101) as "Last Sign On", DateDiff('d', LastSignOn, getDate()) as "Days since last sign on", AddrLine1 + ' ' + AddrLine2 + ' ' + AddrLine3 + ' ' + City + ', ' + State + ' ' + Zip as "Address", 'XXX-XX-' + Substring( Convert(varchar(9), SSN), 6, 4) as "Social Security #" FROM Users 

आम तौर पर, प्रोग्रामर ऐसा करते हैं क्योंकि वे अपने डेटासेट को सीधे ग्रिड में बाँध करने का इरादा रखते हैं, और क्लाइंट पर प्रारूप की तुलना में एसक्यूएल सर्वर प्रारूप सर्वर-साइड के लिए सुविधाजनक है।

उपरोक्त दिखाए गए प्रश्नों की तरह बहुत भंगुर हैं क्योंकि वे यूआई परत में डेटा परत को कसकर जोड़ते हैं। उस के ऊपर, प्रोग्रामिंग की यह शैली पूरी तरह से पुन: प्रयोज्य होने से संग्रहित प्रक्रियाओं को रोकती है।

ये मेरी शीर्ष 3 हैं

नंबर 1. फ़ील्ड सूची निर्दिष्ट करने में विफलता। (संपादित करें: भ्रम को रोकने के लिए: यह एक उत्पादन कोड नियम है। यह एक बार विश्लेषण स्क्रिप्ट पर लागू नहीं होता है – जब तक कि मैं लेखक नहीं हूं।)

 SELECT * Insert Into blah SELECT * 

होना चाहिए

 SELECT fieldlist Insert Into blah (fieldlist) SELECT fieldlist 

संख्या 2. कर्सर का प्रयोग करते समय और पाश, जबकि एक लूप वैरिएबल के साथ एक समय का लूप होगा।

 DECLARE @LoopVar int SET @LoopVar = (SELECT MIN(TheKey) FROM TheTable) WHILE @LoopVar is not null BEGIN -- Do Stuff with current value of @LoopVar ... --Ok, done, now get the next value SET @LoopVar = (SELECT MIN(TheKey) FROM TheTable WHERE @LoopVar < TheKey) END 

संख्या 3. स्ट्रिंग प्रकारों के माध्यम से तिथिलॉगिक।

 --Trim the time Convert(Convert(theDate, varchar(10), 121), datetime) 

होना चाहिए

 --Trim the time DateAdd(dd, DateDiff(dd, 0, theDate), 0) 

मैंने हाल ही में "एक क्वेरी दो की तुलना में बेहतर है, अमरीरा?"

 SELECT * FROM blah WHERE (blah.Name = @name OR @name is null) AND (blah.Purpose = @Purpose OR @Purpose is null) 

पैरामीटर के मूल्यों के आधार पर इस क्वेरी के लिए दो या तीन अलग-अलग निष्पादन योजनाएं आवश्यक हैं केवल एक निष्पादन योजना बनाई गई है और इस एसक्यूएल पाठ के लिए कैश में फंस गया है। पैरामीटर के मूल्य की परवाह किए बिना उस योजना का उपयोग किया जाएगा यह आंतरायिक खराब प्रदर्शन में परिणाम है। यह दो प्रश्नों (एक क्वेरी प्रति इरादा निष्पादन योजना) लिखना बेहतर है।

  • मानव पठनीय पासवर्ड फ़ील्ड , ईदद आत्म व्याख्यात्मक

  • अनुक्रमित कॉलम के खिलाफ की तरह प्रयोग करना, और मुझे लगभग सामान्य रूप में बस कहना पसंद है।

  • एसक्यूएल जनरेटेड पीके मूल्य पुनरावृत्ति

  • आश्चर्य की बात है कि कोई भी ईश्वर तालिका का अभी तक उल्लेख नहीं करता। कुछ भी नहीं "ऑर्गेनिक" बिट झंडे, बड़े तार और पूर्णांक के 100 कॉलम की तरह कहते हैं।

  • फिर "I miss miss .i files" पैटर्न: बड़े अक्षरों में CSVs, पाइप सीमांकित स्ट्रिंग्स या अन्य पार्स की आवश्यक डेटा संग्रहीत करें।

  • और एमएस एसक्यूएल सर्वर के लिए बिल्कुल कर्सर का उपयोग। कोई भी कर्सर कार्य करने का एक बेहतर तरीका है।

क्योंकि बहुत सारे हैं संपादित!

इसके लिए गहरी खुदाई न करें: तैयार बयान का उपयोग न करें।

अर्थहीन तालिका उपनामों का उपयोग करना:

 from employee t1, department t2, job t3, ... 

एक बड़ी एसक्यूएल कथन को पढ़ना बहुत ज़्यादा कठिन है

 var query = "select COUNT(*) from Users where UserName = '" + tbUser.Text + "' and Password = '" + tbPassword.Text +"'"; 
  1. अंधेरे में विश्वास करते हुए उपयोगकर्ता इनपुट
  2. पैरामीटेटेड क्वेरीज़ का उपयोग नहीं करना
  3. क्लेटाटेक्स्ट पासवर्ड

मेरे बगबीरस 450 कॉलम एक्सेस टेबल हैं जो प्रबंध निदेशक के सबसे अच्छे मित्र कुत्ते groomer के 8 साल के बेटे और एक बेजोड़ लुकअप तालिका के एक साथ रखे हुए हैं क्योंकि केवल मौजूद है क्योंकि किसी को पता नहीं है कि कैसे एक डेटास्ट्रैक्चर को सामान्य रूप से सामान्य बनाने के लिए

आमतौर पर, यह लुकअप तालिका इस प्रकार दिखती है:

 मैंने नहीं किया,
 नाम NVARCHAR (132),
 IntValue1 INT,
 IntValue2 INT,
 चारवैल 1 एनवीआरएआरएआर (255),
 चारवील 2 एनवीएचएआरएआर (255),
 दिनांक 1 DATETIME,
 दिनांक 2 DATETIME

मैंने उन ग्राहकों की संख्या की गिनती खो दी है जिन्हें मैंने देखा है कि ऐसे सिस्टम हैं जो इस तरह घृणितता पर भरोसा करते हैं।

जिन लोगों को मैं सबसे अधिक पसंद नहीं करता हूं वे हैं

  1. तालिकाओं का निर्माण करते समय रिक्त स्थान का उपयोग करना, sprocs आदि। मैं कैमल सीज़ या अंडरस्कोप और एकवचन या बहुवचन और अपरैक्सेज़ या लोअरकेस के साथ ठीक हूं लेकिन एक तालिका या स्तंभ [स्थान के साथ] का उल्लेख करना है, खासकर अगर [यह अजीब तरह से है] (हाँ, मैं इस में भाग लिया है) वास्तव में मुझे परेशान

  2. Denormalized डेटा एक तालिका को पूरी तरह से सामान्यीकृत नहीं करना पड़ता है, लेकिन जब मैं अपने मौजूदा मूल्यांकन स्कोर या उनकी प्राथमिक चीज़ों के बारे में जानकारी रखने वाले कर्मचारियों की एक तालिका में चला जाता हूं, तो यह मुझे बताता है कि मुझे शायद कुछ बिंदु पर एक अलग तालिका बनाने की आवश्यकता होगी और फिर उन्हें समन्वयित रखने का प्रयास करें मैं पहले डेटा को सामान्य कर दूंगा और तब अगर मैं एक जगह देखना चाहूँगा जहां denormalization मदद करता है, मैं इसे पर विचार करेंगे

  3. या तो विचार या कर्सर के अति प्रयोग दृश्यों का उद्देश्य है, लेकिन जब प्रत्येक तालिका को एक दृश्य में लपेटा जाता है तो यह बहुत अधिक है मुझे कई बार कर्सर का उपयोग करना पड़ा, लेकिन आम तौर पर आप इसके लिए अन्य तंत्र का उपयोग कर सकते हैं।

  4. पहुंच। क्या कोई प्रोग्राम एक विरोधी-पैटर्न हो सकता है? मेरे पास मेरे काम पर SQL सर्वर है, लेकिन बहुत से लोग उपयोग की वजह से इसकी उपलब्धि का उपयोग करते हैं, "उपयोग में आसानी" और गैर-तकनीकी उपयोगकर्ताओं के लिए "मित्रता"। यहां जाने के लिए बहुत अधिक है, लेकिन अगर आप एक समान वातावरण में हैं, तो आप जानते हैं

अस्थायी तालिकाओं और कर्सर का अति प्रयोग

सपा को दुकान प्रक्रिया नाम के उपसर्ग के रूप में उपयोग करें क्योंकि यह पहले कस्टम प्रक्रियाओं के बजाय सिस्टम प्रक्रिया स्थान में खोज करेगा।

समय मूल्यों को संग्रहीत करने के लिए, केवल UTC समयक्षेत्र का उपयोग किया जाना चाहिए। स्थानीय समय का उपयोग नहीं किया जाना चाहिए।

 select some_column, ... from some_table group by some_column 

और यह मानते हुए कि परिणाम some_column द्वारा सॉर्ट किया जाएगा। मैंने इसे साइबेस के साथ थोड़ा सा देखा है जहां धारणा धारण की गई है (अभी के लिए)

SCOPE_IDENTITY के बजाय @@ पहचान का उपयोग करना ()

इस उत्तर से उद्धरित:

  • @@ की पहचान सभी स्कोप में वर्तमान सत्र में किसी भी तालिका के लिए उत्पन्न अंतिम पहचान मान देता है आपको यहाँ सावधान रहने की आवश्यकता है, क्योंकि यह पूरे स्कोप में है आप अपने वर्तमान कथन के बजाय एक ट्रिगर से मूल्य प्राप्त कर सकते हैं
  • SCOPE_IDENTITY वर्तमान सत्र में मौजूद किसी भी तालिका के लिए उत्पन्न अंतिम पहचान मूल्य और वर्तमान दायरे को वापस देता है। आम तौर पर आप क्या उपयोग करना चाहते हैं
  • IDENT_CURRENT किसी भी सत्र और किसी भी क्षेत्र में किसी विशेष तालिका के लिए उत्पन्न अंतिम पहचान मान देता है यह आपको निर्दिष्ट करता है कि आप किस तालिका से मूल्य चाहते हैं, इसके बाद के संस्करण दो की अपेक्षा काफी नहीं है (बहुत दुर्लभ)। आप इसका उपयोग तब कर सकते हैं यदि आप एक तालिका के लिए मौजूदा पहचान मूल्य प्राप्त करना चाहते हैं जिसमें आपने रिकॉर्ड दर्ज नहीं किया है।

कुछ के लिए 'मृत' फ़ील्ड का पुनः उपयोग करना जिसका उद्देश्य यह नहीं था (उदाहरण के लिए एक 'फैक्स' फ़ील्ड में उपयोगकर्ता डेटा संग्रहीत करना) – हालांकि एक त्वरित सुधार के रूप में बहुत आकर्षक!

 SELECT FirstName + ' ' + LastName as "Full Name", case UserRole when 2 then "Admin" when 1 then "Moderator" else "User" end as "User's Role", case SignedIn when 0 then "Logged in" else "Logged out" end as "User signed in?", Convert(varchar(100), LastSignOn, 101) as "Last Sign On", DateDiff('d', LastSignOn, getDate()) as "Days since last sign on", AddrLine1 + ' ' + AddrLine2 + ' ' + AddrLine3 + ' ' + City + ', ' + State + ' ' + Zip as "Address", 'XXX-XX-' + Substring(Convert(varchar(9), SSN), 6, 4) as "Social Security #" FROM Users 

या, एक पंक्ति में सब कुछ cramming

  • FROM TableA, TableB WHEREFROM TableA, TableB WHERE लिए जेनरेट करने के लिए वाक्य रचना

  • मान्यताओं को बनाते हुए कि किसी प्रश्न को एक विशिष्ट तरीके से क्रम में ORDER BY खंड लगाए बिना लौटा दिया जाएगा, सिर्फ इसलिए कि यह क्वेरी टूल में परीक्षण के दौरान दिखाया गया था।

मुझे अपना खुद का पसंदीदा यहाँ रखना होगा, बस सूची को पूरा करने के लिए मेरा पसंदीदा antipattern आपके प्रश्नों का परीक्षण नहीं कर रहा है

यह तब लागू होता है जब:

  1. आपकी क्वेरी में एक से अधिक तालिका शामिल है।
  2. आपको लगता है कि आपके पास एक क्वेरी के लिए एक इष्टतम डिजाइन है, लेकिन अपनी मान्यताओं का परीक्षण करने के लिए परेशान न करें।
  3. आप पहली क्वेरी को स्वीकार करते हैं जो काम करता है, इस बारे में कोई सुराग नहीं है कि यह ऑप्टिमाइज़ किए गए के करीब है या नहीं।

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

अपने कैरियर के पहले छह महीनों में एसक्यूएल सीखना और अगले 10 वर्षों के लिए कुछ और सीखना कभी नहीं। विशेष रूप से विंडोिंग / विश्लेषणात्मक एसक्यूएल विशेषताओं का प्रयोग या प्रभावी ढंग से नहीं विशेष रूप से ओवर () और विभाजन का उपयोग करके

विंडो फ़ंक्शंस, जैसे कुल कार्य, पंक्तियों के किसी निर्धारित सेट (एक समूह) पर एक एकत्रीकरण करते हैं, लेकिन प्रति समूह एक मूल्य लौटने की बजाय, विंडो फ़ंक्शंस प्रत्येक समूह के लिए एकाधिक मान वापस कर सकते हैं।

विंडोिंग फ़ंक्शंस का एक अच्छा सिंहावलोकन के लिए ओ रेली एसक्यूएल कुकबुक परिशिष्ट ए देखें।

Contrarian दृश्य: सामान्यीकरण के साथ अधिक जुनून।

ज्यादातर एसक्यूएल / आरबीडीबी सिस्टम एक बहुत सारी विशेषताएं (लेन-देन, प्रतिकृति) देते हैं जो काफी उपयोगी होते हैं, यहां तक ​​कि असमान डेटा के साथ भी। डिस्क स्पेस सस्ता है, और कभी-कभी यह 1 एनएफ़ स्कीमा लिखने की तुलना में हेरफेर करने / फ़िल्टर / खोज किए गए डेटा को हेरफेर करने के लिए आसान और आसान (आसान कोड, तेज विकास का समय) हो सकता है, और उसमें सभी परेशानियों से निपटना (जटिल मिलती है, गंदा उपशैली , आदि)।

मैंने पाया है कि अधिक सामान्यीकृत सिस्टम अक्सर समय से पहले अनुकूलन होते हैं, खासकर प्रारंभिक विकास चरणों के दौरान।

(इस पर अधिक विचार … http://writeonly.wordpress.com/2008/12/05/simple-object-db-using-json-and-python-sqlite/ )

मैं बस इस एक साथ डाल दिया, कुछ एसक्यूएल प्रतिक्रियाओं के आधार पर यहाँ एसओ पर।

यह सोचने के लिए एक गंभीर विरोधी है कि ट्रिगर डेटाबेस के रूप में होते हैं क्योंकि ईवेंट हैंडलर OOP हैं इस धारणा है कि किसी भी पुराने तर्क को ट्रिगर्स में डाल दिया जा सकता है, जब एक मेज पर लेनदेन (घटना) होता है तो उसे निकाल दिया जाए।

सच नहीं। बड़ा अंतर यह है कि ट्रिगर तुल्यकालिक हैं – एक प्रतिशोध के साथ, क्योंकि वे किसी सेट ऑपरेशन पर तुल्यकालिक हैं, एक पंक्ति ऑपरेशन पर नहीं ओओपी पक्ष पर, बिल्कुल विपरीत – घटनाएं अतुल्यकालिक लेनदेन को लागू करने का एक कारगर तरीका है।

अस्थाई टेबल दुरुपयोग

विशेष रूप से इस तरह की बात:

 SELECT personid, firstname, lastname, age INTO #tmpPeople FROM People WHERE lastname like 's%' DELETE FROM #tmpPeople WHERE firstname = 'John' DELETE FROM #tmpPeople WHERE firstname = 'Jon' DELETE FROM #tmpPeople WHERE age > 35 UPDATE People SET firstname = 'Fred' WHERE personid IN (SELECT personid from #tmpPeople) 

किसी क्वेरी से अस्थायी तालिका का निर्माण न करें, केवल उन पंक्तियों को हटाने के लिए जिन्हें आपको आवश्यकता नहीं है।

और हां, मैंने इस फॉर्म में कोड के पन्नों को उत्पादन डीबीज़ में देखा है।

1) मुझे नहीं पता है कि यह एक "आधिकारिक" विरोधी-पैटर्न है, लेकिन मैं एक डेटाबेस कॉलम में मैजिक वैल्यू के रूप में स्ट्रिंग लीटरल्स को नापसंद करने की कोशिश करता हूं।

मिडियाविकी की मेज 'छवि' से एक उदाहरण:

 img_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL, img_major_mime ENUM("unknown", "application", "audio", "image", "text", "video", "message", "model", "multipart") NOT NULL default "unknown", 

(मैं सिर्फ अलग आवरण नोटिस, एक और बात से बचने के लिए)

मैं ऐसे मामलों को इंट प्राथमिक कुंजी के साथ तालिका में इंट लुकअप के रूप में चित्रित करता है छविमेडिया टाइप और इमेज मेजरमैम।

2) तारीख / स्ट्रिंग रूपांतरण जो विशिष्ट एनएलएस सेटिंग्स पर निर्भर करता है

 CONVERT(NVARCHAR, GETDATE()) 

प्रारूप पहचानकर्ता के बिना

एक क्वेरी में समान subqueries।

  • बदलते व्यू – एक ऐसा दृश्य जिसे अक्सर नोटिस या कारण के बिना बदल दिया जाता है। परिवर्तन या तो सबसे अनुचित समय पर गौर किया जाएगा या बुरा होगा और कभी भी ध्यान नहीं दिया जाएगा। हो सकता है कि आपका आवेदन टूट जाएगा क्योंकि किसी ने उस कॉलम के लिए बेहतर नाम के बारे में सोचा। उपभोक्ताओं के साथ एक अनुबंध बनाए रखते हुए एक नियम के रूप में आधार तालिकाओं की उपयोगिता बढ़ाना चाहिए। समस्याओं को ठीक करें, लेकिन सुविधाओं या बदतर बदलाव व्यवहार न करें, इसके लिए एक नया दृश्य बनाएं कम करने के लिए अन्य परियोजनाओं के साथ विचार साझा नहीं करते हैं, और जब प्लेटफॉर्म की अनुमति होती है तो सीटीई का उपयोग करें यदि आपकी दुकान में डीबीए है तो आप शायद विचार बदल नहीं सकते हैं, लेकिन आपके सभी विचार पुराने और या तो बेकार होंगे।

  • ! पैरामेड – क्या एक क्वेरी में एक से अधिक उद्देश्य हो सकते हैं? संभवतः लेकिन अगले व्यक्ति जो इसे पढ़ता है, वह तब तक नहीं पता होगा जब तक कि गहन ध्यान नहीं। यहां तक ​​कि अगर आपको उनकी ज़रूरत नहीं है, तो अभी भी संभावनाएं हैं, भले ही यह सिर्फ "डिबग" करने के लिए है पैरामीटर जोड़ना, रखरखाव के समय को कम करता है और चीजों को सूखा रखता है यदि आपके पास एक ऐसा नियम है जिसमें आपको पैरामीटर चाहिए

  • कोई मामला नहीं है –

     SELECT CASE @problem WHEN 'Need to replace column A with this medium to large collection of strings hanging out in my code.' THEN 'Create a table for lookup and add to your from clause.' WHEN 'Scrubbing values in the result set based on some business rules.' THEN 'Fix the data in the database' WHEN 'Formating dates or numbers.' THEN 'Apply formating in the presentation layer.' WHEN 'Createing a cross tab' THEN 'Good, but in reporting you should probably be using cross tab, matrix or pivot templates' ELSE 'You probably found another case for no CASE but now I have to edit my code instead of enriching the data...' END 

बिना किसी टिप्पणी के संग्रहित प्रक्रियाओं या कार्य …

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

दोनों मैं सबसे ज्यादा मिल रहा हूं, और प्रदर्शन के संदर्भ में एक महत्वपूर्ण लागत हो सकती है:

  • किसी सेट आधारित अभिव्यक्ति के बजाय कर्सर का उपयोग करना मुझे लगता है कि ऐसा अक्सर होता है जब प्रोग्रामर प्रक्रियात्मक रूप से सोच रहा है

  • सहसंबद्ध उप-प्रश्नों का उपयोग करते समय, जब कोई व्युत्पन्न तालिका में शामिल हो सकता है, तो वह काम कर सकता है।

Developers who write queries without having a good idea about what makes SQL applications (both individual queries and multi-user systems) fast or slow. This includes ignorance about:

  • physical I/O minimization strategies, given that most queries' bottleneck is I/O not CPU
  • perf impact of different kinds of physical storage access (eg lots of sequential I/O will be faster than lots of small random I/O, although less so if your physical storage is an SSD!)
  • how to hand-tune a query if the DBMS produces a poor query plan
  • how to diagnose poor database performance, how to "debug" a slow query, and how to read a query plan (or EXPLAIN, depending on your DBMS of choice)
  • locking strategies to optimize throughput and avoid deadlocks in multi-user applications
  • importance of batching and other tricks to handle processing of data sets
  • table and index design to best balance space and performance (eg covering indexes, keeping indexes small where possible, reducing data types to minimum size needed, etc.)

Using SQL as a glorified ISAM (Indexed Sequential Access Method) package. In particular, nesting cursors instead of combining SQL statements into a single, albeit larger, statement. This also counts as 'abuse of the optimizer' since in fact there isn't much the optimizer can do. This can be combined with non-prepared statements for maximum inefficiency:

 DECLARE c1 CURSOR FOR SELECT Col1, Col2, Col3 FROM Table1 FOREACH c1 INTO a.col1, a.col2, a.col3 DECLARE c2 CURSOR FOR SELECT Item1, Item2, Item3 FROM Table2 WHERE Table2.Item1 = a.col2 FOREACH c2 INTO b.item1, b.item2, b.item3 ...process data from records a and b... END FOREACH END FOREACH 

The correct solution (almost always) is to combine the two SELECT statements into one:

 DECLARE c1 CURSOR FOR SELECT Col1, Col2, Col3, Item1, Item2, Item3 FROM Table1, Table2 WHERE Table2.Item1 = Table1.Col2 -- ORDER BY Table1.Col1, Table2.Item1 FOREACH c1 INTO a.col1, a.col2, a.col3, b.item1, b.item2, b.item3 ...process data from records a and b... END FOREACH 

The only advantage to the double loop version is that you can easily spot the breaks between values in Table1 because the inner loop ends. This can be a factor in control-break reports.

Also, sorting in the application is usually a no-no.

I just came across view definition like this:

 CREATE OR REPLACE FORCE VIEW PRICE (PART_NUMBER, PRICE_LIST, LIST_VERSION ...) AS SELECT sp.MKT_PART_NUMBER, sp.PRICE_LIST, sp.LIST_VERSION, sp.MIN_PRICE, sp.UNIT_PRICE, sp.MAX_PRICE, ... 

There are 50 or so columns in the view. Some developers take a small pride torturing others by not providing column aliases, so one have to count column offset in both places in order to be able to figure out what column in a view corresponds to.