Десет общи SQL програмиране грешки

Прекомерната употреба на курсори

SQL-програмиране може да бъде вълнуваща и предизвикателна задача. Хората, които имат опит в програмирането на традиционните езици за програмиране като Java, C, C ++ или VB, често имат трудности да се приспособят към "определени на базата на" е образът на мисълта. Дори и опитни програмисти и SQL-DBA могат да попадат в една от капаните на езика SQL. Аз бях там, и аз се обзалагам, че ще прекалено. Изучаването на основите отнема време, а дори и с някои грешки, трудни за проследяване.

В тази статия, аз възнамерявам да подчертае някои от най-честите грешки, направени от хора, които пишат SQL-код. Списъкът отразява моя опит от работа с различни екипи от разработчици и програмисти, извършващи код ревюта и т.н. както и проблемите, обсъждането на която аз всеки ден виждам във форумите. Това не е изчерпателен списък, както и грешки в него не се сортират. В действителност, този списък може да се разглежда като резултат от следната заявка:

Ето списъка:

  1. NULL НЕ ПО предикат.
  2. Функция за индексирана колона в предикати.
  3. Неизправност на колоната в подзаявка.
  4. Несъответствието между типовете данни в предикатите.
  5. Редът на оценка на предикати.
  6. Външни връзки (външна присъединява) и поставяне на предиката.
  7. Подзаявки, които връщат повече от един резултат.
  8. Използване на SELECT *.
  9. Скаларни ФГР.
  10. Прекомерната употреба на курсора.

Примерите използват Transact-SQL диалекта, но повечето от концепциите са полезни за всеки изпълнение SQL.

NULL, а не в предикат

Един от най-честите заявки - избор на базата на определена стойност на колоната не е част от списъка на ценности. Следващите две таблици илюстрират този сценарий. Ние имаме една маса с цветя и храна.

Имайте предвид, че тук @last_name параметър NVARCHAR на тип данни. Код "работи", но SQL Server ще трябва да направите, за мълчалив имена на колони превръщане в NVARCHAR, както NVARCHAR - по-висок приоритет тип данни. Това може да доведе до загуба на производителност. Скритият преобразуване се показва в плана за заявка като CONVERT_IMPLICIT. В зависимост от сорта, както и други фактори на несъответствие на типовете данни също могат да попречат на използването на търсене в показалеца. Използването на правилния тип данни решава проблема:

В много случаи тази грешка е резултат от споделена отговорност в екип, където един от членовете на екипа е проектиране таблици и други приспособления, съхранени процедури или писане на код. Друга причина може да бъде данни съединение от различни източници, в които някои колони могат да имат различни типове данни. Същата препоръка е приложима не само за грешки при вида на символите данни, но също така да несъответствията на числени типове данни (например INT и FLOAT), или да се смесване числови и азбучни видове.

Редът на оценка на предикати

Ако сте запознати с логическата реда на обработка на заявката ви, може да се очаква, че заявката се извършва в следния ред:

Тази последователност е описана логически реда на заявката. ОТ израз логично обработват първо, определяне на първоначалния набор от данни след това се прилага предикати КЪДЕ, GROUP BY тях и т.н.

Въпреки това, исканията се обработват не са физически добре и оптимизатора на заявки могат да се движат свободно изразяване в плана за заявка за постигане на най-ефективния и данни разходите за плана за вземане на проби. Това води до популярното схващане, че филтърът в условия, когато са приложими към преработката на следващата фаза. В действителност, на физическо ниво в предиката на заявката може да се прилага много по-късно. В допълнение, за изпълнението на предиката не е ред от ляво на дясно. Например, ако имате израз на къде, съдържащ "където х = 1 и у = 2", няма гаранция, че "х = 1" ще се счита на първо място. Те могат да бъдат изпълнени в произволен ред.

Като цяло, една маса с лош дизайн. Колона account_reference бъдат представени като две различни атрибут отделно за бизнес- и Лични сметки, всеки правилен тип данни (и дори не принадлежат към тази таблица). Въпреки това, на практика често се налага да се справят с лошо проектирани системи, дизайнът на които не можем да променим.

За да коригирате първоначалното искане, е достатъчно, за да преместите КЪДЕ сказуемото в състояние присъединят.

Сега поиска да даде правилния резултат, тъй като Джеф и Джули филтрира предикати се присъединят, но след това се върнете назад, когато външни линии връщане.

В по-сложна например с няколко връзки може да се получи неправилно филтриране в следните оператори маса (например, съединения с друга маса), но не в клаузата WHERE. Да предположим, че имаме една маса на ORDERDETAILS, съдържащ единица за продукта и количество. Искането трябва да даде списък на всички клиенти, обемът на реда и размера за избрания складови единици. Следната заявка изглежда е вярна:

Въпреки това, има INNER JOIN с ORDERDETAILS маса играе точно същата роля като WHERE клаузата в примера по-горе, в смисъл, превръщайки лявата външна JOIN във вътрешната JOIN. Валидна заявка, която отговаря на изискванията, е да се използва НАЛЯВО JOIN да се свърже с ORDERDETAILS маса:

Подзаявки, които връщат повече от една стойност

Често се изисква за получаване на определена стойност въз основа на корелацията с главната таблица на заявка. Например, обърнете внимание на следните две таблици, които съхраняват информация за продуктите и фабриките, които произвеждат тези продукти.

Имайте предвид, че същата грешка може да се появи в предиката когато се сравнява колона или експресия с подзаявка, например, "... колона = (SELECT стойност от таблица)". В този случай решението е да се използва в предиката вместо "=".

Използване на SELECT *

Когато за първи път се срещна с SQL ние винаги се надигаш на гений, който изобрети SELECT * синтаксис! Тя е толкова удобен и лесен за използване! Вместо изрично изброява всички имена на колоните в заявката, е достатъчно да използвате магическа маска "*" и да получите всички колони. Например, широко злоупотреба SELECT * - отстраняване на всички пластмасови продукти, за да бъдат включени в друга маса със същата структура:

Всичко е готово! Въпреки това, след промяната на изискванията в Продуктите маса ще видите две нови колони:

Ситуацията може да бъде дори по-лошо, ако използвате SELECT * създава изглед, а след това в основата се добавят таблици (или премахнато) колона.

Забележка: Ако оглед е създаден с помощта на опцията SCHEMABINDING, базовите таблици не могат да бъдат променени така, че да се отрази на определението за оглед.

За да приключите, не използвайте SELECT * в производството код! Изключение може да бъде използването на СЪЩЕСТВУВА предикат. В списъка за избор на подзаявка за съществува предикат се игнорира, защото е важно само за линии.

Скаларни ФГР

Повторно използване на код - един от основните принципи, които се учат при програмирането на всеки език, както и SQL - не е изключение. Тя осигурява много инструменти, за да можете да се логично група кода помогне и да го използвате многократно.

Един такъв инструмент в SQL Server - скаларни ФГР. Изглежда много удобно да се скрие всички сложни изчисления във функцията, и след това просто го наричат ​​в запитвания. Въпреки това, скрит недостатък е, че тя може да доведе до значителна загуба на производителност. Когато се използва в заявката скаларни функции се изчисляват за всеки ред. За по-големи маси това може да доведе до много бавни заявки да се изпълняват. Това е особено вярно, когато скаларна функция трябва да се прилага за данните на друга маса.

Ето един пример. Съдържа таблици с продуктите и техните продажби, които искате да получите общите продажби за всеки продукт. Тъй като стойността на сумата на продажбите може да се използва и на други места, че решите да използвате скаларна функция за изчисляване на общия обем на продажбите на продукта: