Я последовательно разочаровываюсь тенденцией большинства программистов смешать их логику UI на уровне доступа к данным:
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
Обычно, программисты делают это, потому что они намереваются связать свой набор данных непосредственно с сеткой, и ее просто удобный для имения SQL Server форматируют серверную сторону, чем формат на клиенте.
Запросы как один показанный выше является чрезвычайно хрупким, потому что они сильно связывают слой данных к уровню UI. Вдобавок ко всему, этот стиль программирования полностью препятствует тому, чтобы хранимые процедуры были допускающими повторное использование.
Измененное Представление - представление, которое изменяется слишком часто и без уведомления или причины. Изменение будет или замечено в самое несоответствующее время или хуже никогда не быть неправильно и замеченным. Возможно, Ваше приложение повредится, потому что кто-то думал о лучшем названии того столбца. Как правило, представления должны расширить полноценность базовых таблиц при поддержании контракта с потребителями. Решите проблемы, но не добавляйте опции или худшее поведение изменения, поскольку это создает новое представление. Для смягчения не разделяют взгляды с другими проектами и, используют CTEs, когда платформы позволяют. Если Ваш магазин имеет DBA, Вы, вероятно, не можете изменить представления, но все Ваши представления устареют и или будут бесполезны в этом случае.
! Paramed - запрос может иметь больше чем одну цель? Вероятно, но следующий человек, который читает его, не будет знать до глубокой медитации. Даже если Вам не нужны они прямо сейчас, возможности - Вы, будет, даже если это должно "только" отладить. Добавление параметров понижает время обслуживания, и сохраните вещи DRY. Если Вы имеете, где пункт у Вас должны быть параметры.
случай ни для какого СЛУЧАЯ -
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
Два я нахожу большинство и могу иметь значительную стоимость с точки зрения производительности:
Используя курсоры вместо основанного на наборе выражения. Я предполагаю, что этот происходит часто, когда программист думает procedurely.
Используя связанные подзапросы, когда соединение к полученной таблице может сделать задание.
Помещение материала во временных таблицах, особенно люди, которые переключаются от SQL Server до Oracle, имеет привычку к злоупотреблению временных таблиц. Просто используйте вложенные избранные операторы.
Используя SQL как прославленный ISAM (Индексно-последовательный метод доступа) пакет. В частности, вложенные курсоры вместо того, чтобы комбинировать SQL-операторы в сингл, хотя больше, оператор. Это также рассчитывает как 'злоупотребление оптимизатором' с тех пор на самом деле нет очень оптимизатора, может сделать. Это может быть объединено с неподготовленными операторами для максимальной неэффективности:
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
правильное решение (почти всегда) должно объединить эти два оператора SELECT в один:
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
единственное преимущество для двойной версии цикла состоит в том, что можно легко определить повреждения между значениями в Table1, потому что внутренний цикл заканчивается. Это может быть фактором в отчетах по нажатию Ctrl-Break.
кроме того, сортируя в приложении обычно нет - нет.
1) я не знаю, что это - "официальный" антишаблон, но я не люблю и стараюсь избегать строковых литералов, поскольку волшебство оценивает в столбце базы данных.
пример от таблицы MediaWiki 'изображение':
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",
(я просто замечаю различное преобразование регистра, другая вещь избежать)
я разрабатываю такие случаи как международные поиски в таблицы ImageMediaType и ImageMajorMime с международными первичными ключами.
2) дата/преобразование строк, которая полагается на определенные настройки NLS
CONVERT(NVARCHAR, GETDATE())
без идентификатора формата
Я просто соединил этого, на основе некоторых ответов SQL здесь на ТАК.
Это - серьезный антишаблон, чтобы думать, что триггеры к базам данных, как обработчики событий к ООП. Существует это восприятие, что просто любая старая логика может быть помещена в триггеры, чтобы быть исчерпанной, когда транзакция (событие) происходит на таблице.
Не верный. Одни из больших различий - то, что триггеры синхронны - с удвоенной силой, потому что они синхронны на операции присвоения, не на операции строки. На стороне ООП точно противоположное - события являются эффективным способом реализовать асинхронные транзакции.
Противоположное представление: сверходержимость нормализацией.
Большинство систем SQL/RBDBs дает партии функций (транзакции, репликация), которые довольно полезны, даже с ненормализованными данными. Дисковое пространство является дешевым, и иногда может быть более просто (более легкий код, более быстрое время разработки) управлять / фильтр / поисковые выбранные данные, чем это должно описать схему на 1 нФ и соглашение со всеми стычками там (сложные соединения, противные подвыборы, и т.д.).
я нашел, что сверхнормализованные системы часто являются преждевременной оптимизацией, особенно во время ранних стадий разработки.
(больше мыслей о нем... http://writeonly.wordpress.com/2008/12/05/simple-object-db-using-json-and-python-sqlite/ )
Вот мои лучшие 3.
Номер 1. Отказ определить cписок полей. (Редактирование: предотвратить беспорядок: это - производственное правило кода. Это не относится к одноразовым аналитическим сценариям - если я не автор.)
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. DateLogic через строковые типы.
--Trim the time
Convert(Convert(theDate, varchar(10), 121), datetime)
Должен быть
--Trim the time
DateAdd(dd, DateDiff(dd, 0, theDate), 0)
<час> , я видел, что недавний скачок "Одного запроса лучше, чем два, amiright?"
SELECT *
FROM blah
WHERE (blah.Name = @name OR @name is null)
AND (blah.Purpose = @Purpose OR @Purpose is null)
Этот запрос требует двух или трех различных планов выполнения в зависимости от значений параметров. Только один план выполнения сгенерирован и вонзен кэш для этого sql текста. Тот план будет использоваться независимо от значения параметров. Это приводит к неустойчивой низкой производительности. Намного лучше записать два запроса (один запрос на намеченный план выполнения).
Человекочитаемые поля пароля , ей-богу. Сам объяснительный.
Используя [1 116] КАК против индексируемого столбцы, и я почти испытываю желание просто сказать КАК в целом.
Перерабатывающие сгенерированные SQL значения PK.
Удивление никто еще не упомянул таблица бога . Ничто не говорит "органический" как 100 столбцов битовых флагов, больших строк и целых чисел.
Тогда существует , "Я пропускаю .ini файлы" шаблон: хранение CSVs, канал разграничил строки, или другой синтаксический анализ потребовал данных в полях крупного текста.
И для SQL-сервера MS использование курсоров во всем . Существует лучший способ сделать любую данную задачу курсора.
Отредактированный, потому что существуют так многие!
Не должны рыть глубоко для него: Не использование подготовленных операторов.
Используя бессмысленные псевдонимы таблицы:
from employee t1,
department t2,
job t3,
...
Делает чтение большого SQL-оператора настолько тяжелее, чем это должно быть
var query = "select COUNT(*) from Users where UserName = '"
+ tbUser.Text
+ "' and Password = '"
+ tbPassword.Text +"'";
Мои проблемы являются таблицами 450 столбцов Access, которые были соединены 8-летним сыном грумера собаки лучших друзей исполнительного директора и изворотливой таблицы поиска, которая только существует, потому что кто-то не знает, как нормализовать datastructure правильно.
Как правило, эта таблица поиска похожа на это:
ID INT, Name NVARCHAR(132), IntValue1 INT, IntValue2 INT, CharValue1 NVARCHAR(255), CharValue2 NVARCHAR(255), Date1 DATETIME, Date2 DATETIME
я потерял счет числу клиентов, которые я видел, у кого есть системы, которые полагаются на отвращение как это.
Те, что мне не нравится большинство,
Используя пробелы при составлении таблиц, sprocs и т.д. Все хорошо с CamelCase или under_scores и исключительный или множественные числа и ВЕРХНИЙ РЕГИСТР или нижний регистр, но имея необходимость относиться к таблице или столбцу [с пробелами], особенно если [это странно расположено с интервалами] (да, я столкнулся с этим) действительно раздражает меня.
Денормализованные данные. Таблица не должна быть отлично нормализована, но когда я сталкиваюсь с таблицей сотрудников, которая имеет информацию об их текущем счете оценки или их основном устройстве что-либо, это говорит мне, что я должен буду, вероятно, сделать отдельную таблицу в какой-то момент и затем попытаться сохранить их синхронизировавшими. Я нормализую данные сначала и затем если я буду видеть место, где денормализация помогает, я рассмотрю его.
Злоупотребление или представлениями или курсорами. Представления имеют цель, но когда каждая таблица обертывается в представление, это слишком много. Я должен был использовать курсоры несколько раз, но обычно можно использовать другие механизмы для этого.
Доступ. Программа может быть антишаблоном? У нас есть SQL Server на моей работе, но много людей используют доступ из-за, он - доступность, "простота использования" и "дружелюбие" нетехническим пользователям. Существует слишком много здесь для входа, но если Вы были в аналогичной среде, Вы знаете.
используйте SP в качестве префикса имени процедуры хранилища, потому что это будет сначала искать в Системном месте процедур, а не пользовательских.
Злоупотребление временными таблицами и курсорами.
FROM TableA, TableB WHERE
синтаксис для СОЕДИНЕНИЙ, а не FROM TableA INNER JOIN TableB ON
предположения Создания, что запрос будет возвращен, отсортировали определенный путь, не вставляя пункт ORDER BY, просто потому что это было способом, которым это обнаружилось во время тестирования в инструментальном средстве формирования запросов.
select some_column, ...
from some_table
group by some_column
и предполагая, что результат будет отсортирован по some_column. Я видел это немного с Sybase, где предположение содержит (на данный момент).
Я должен поместить своего собственного текущего фаворита здесь, только для вхождения в завершенный список. Мой любимый антишаблон не тестирование Ваших запросов .
Это применяется когда:
И любой тестовый прогон против нетипичных или недостаточных данных не рассчитывают. Если это - хранимая процедура, поместило тестовый оператор в комментарий и сохраняет его с результатами. Иначе поместите его в комментарий в коде с результатами.
использование @@ ИДЕНТИФИКАЦИОННЫЕ ДАННЫЕ вместо SCOPE_IDENTITY ()
Заключенный в кавычки из этого ответа:
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
Или, собрав все в одну строку.
Общие ограничения используют «когда» в F #:
type Foo<'a when 'a :> IComparable> =
member x.Bla = 0
- 121 --- 3666100-- Для хранения значений времени следует использовать только часовой пояс UTC. Местное время не должно использоваться.
Злоупотребление временной таблицей.
В частности, такого рода вещи:
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)
Не создавайте временную таблицу из запроса, только для удаления ненужных строк.
И да, я видел страницы кода в этой форме в производственных БД.
Изучать SQL в первые шесть месяцев своей карьеры и никогда больше ничего не изучать в течение следующих 10 лет. В частности, отсутствие обучения или эффективного использования оконных / аналитических функций SQL. В частности, использование over () и partition by.
Оконные функции, как и агрегатные функции, выполняют агрегирование определенного набора (группы) строк, но вместо того, чтобы возвращать одно значение для каждого {{1} }, оконные функции могут возвращать несколько значений для каждой группы.
См. Приложение A «Поваренная книга SQL» O'Reilly для получения хорошего обзора оконных функций.
Re-using a 'dead' field for something it wasn't intended for (e.g. storing user data in a 'Fax' field) - very tempting as a quick fix though!
Только для поддержки Точка 1 из ответа David выезд этот пример ситуации при использовании выбора * может привести к некоторым неожиданным результатам
Присоединение к избыточным таблицам в запрос как это:
select emp.empno, dept.deptno
from emp
join dept on dept.deptno = emp.deptno;
Возможно, не анти-шаблон, но это раздражает меня, когда DBA определенного DB (хорошо я говорю о Oracle здесь) пишет использованию кода SQL Server стиль Oracle и кодирует соглашения и жалуется, когда это работает настолько плохо. Достаточно с курсорами люди Oracle! SQL предназначен, чтобы быть установленным базирующийся.