Каковы наиболее распространенные антишаблоны SQL? [закрытый]

225
задан 6 revs, 2 users 100% 10 September 2010 в 18:06
поделиться

33 ответа

Я последовательно разочаровываюсь тенденцией большинства программистов смешать их логику 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. Вдобавок ко всему, этот стиль программирования полностью препятствует тому, чтобы хранимые процедуры были допускающими повторное использование.

150
ответ дан 3 revs, 2 users 98% 23 November 2019 в 03:53
поделиться

Идентичные подзапросы в запросе.

7
ответ дан EvilTeach 23 November 2019 в 03:53
поделиться
  • Измененное Представление - представление, которое изменяется слишком часто и без уведомления или причины. Изменение будет или замечено в самое несоответствующее время или хуже никогда не быть неправильно и замеченным. Возможно, Ваше приложение повредится, потому что кто-то думал о лучшем названии того столбца. Как правило, представления должны расширить полноценность базовых таблиц при поддержании контракта с потребителями. Решите проблемы, но не добавляйте опции или худшее поведение изменения, поскольку это создает новое представление. Для смягчения не разделяют взгляды с другими проектами и, используют 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  
    
7
ответ дан 2 revs, 2 users 98% 23 November 2019 в 03:53
поделиться

Два я нахожу большинство и могу иметь значительную стоимость с точки зрения производительности:

  • Используя курсоры вместо основанного на наборе выражения. Я предполагаю, что этот происходит часто, когда программист думает procedurely.

  • Используя связанные подзапросы, когда соединение к полученной таблице может сделать задание.

5
ответ дан Mitch Wheat 23 November 2019 в 03:53
поделиться

Помещение материала во временных таблицах, особенно люди, которые переключаются от SQL Server до Oracle, имеет привычку к злоупотреблению временных таблиц. Просто используйте вложенные избранные операторы.

5
ответ дан tuinstoel 23 November 2019 в 03:53
поделиться

Используя 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.

кроме того, сортируя в приложении обычно нет - нет.

3
ответ дан 2 revs 23 November 2019 в 03:53
поделиться

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())

без идентификатора формата

7
ответ дан devio 23 November 2019 в 03:53
поделиться

Я просто соединил этого, на основе некоторых ответов SQL здесь на ТАК.

Это - серьезный антишаблон, чтобы думать, что триггеры к базам данных, как обработчики событий к ООП. Существует это восприятие, что просто любая старая логика может быть помещена в триггеры, чтобы быть исчерпанной, когда транзакция (событие) происходит на таблице.

Не верный. Одни из больших различий - то, что триггеры синхронны - с удвоенной силой, потому что они синхронны на операции присвоения, не на операции строки. На стороне ООП точно противоположное - события являются эффективным способом реализовать асинхронные транзакции.

9
ответ дан dkretz 23 November 2019 в 03:53
поделиться

Противоположное представление: сверходержимость нормализацией.

Большинство систем SQL/RBDBs дает партии функций (транзакции, репликация), которые довольно полезны, даже с ненормализованными данными. Дисковое пространство является дешевым, и иногда может быть более просто (более легкий код, более быстрое время разработки) управлять / фильтр / поисковые выбранные данные, чем это должно описать схему на 1 нФ и соглашение со всеми стычками там (сложные соединения, противные подвыборы, и т.д.).

я нашел, что сверхнормализованные системы часто являются преждевременной оптимизацией, особенно во время ранних стадий разработки.

(больше мыслей о нем... http://writeonly.wordpress.com/2008/12/05/simple-object-db-using-json-and-python-sqlite/ )

9
ответ дан Gregg Lind 23 November 2019 в 03:53
поделиться

Вот мои лучшие 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 текста. Тот план будет использоваться независимо от значения параметров. Это приводит к неустойчивой низкой производительности. Намного лучше записать два запроса (один запрос на намеченный план выполнения).

115
ответ дан 4 revs, 2 users 99% 23 November 2019 в 03:53
поделиться
  • Человекочитаемые поля пароля , ей-богу. Сам объяснительный.

  • Используя [1 116] КАК против индексируемого столбцы, и я почти испытываю желание просто сказать КАК в целом.

  • Перерабатывающие сгенерированные SQL значения PK.

  • Удивление никто еще не упомянул таблица бога . Ничто не говорит "органический" как 100 столбцов битовых флагов, больших строк и целых чисел.

  • Тогда существует , "Я пропускаю .ini файлы" шаблон: хранение CSVs, канал разграничил строки, или другой синтаксический анализ потребовал данных в полях крупного текста.

  • И для SQL-сервера MS использование курсоров во всем . Существует лучший способ сделать любую данную задачу курсора.

Отредактированный, потому что существуют так многие!

68
ответ дан 4 revs 23 November 2019 в 03:53
поделиться

Не должны рыть глубоко для него: Не использование подготовленных операторов.

60
ответ дан stesch 23 November 2019 в 03:53
поделиться

Используя бессмысленные псевдонимы таблицы:

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

Делает чтение большого SQL-оператора настолько тяжелее, чем это должно быть

56
ответ дан Tony Andrews 23 November 2019 в 03:53
поделиться
var query = "select COUNT(*) from Users where UserName = '" 
            + tbUser.Text 
            + "' and Password = '" 
            + tbPassword.Text +"'";
  1. Вслепую доверчивый ввод данных пользователем
  2. Не использование параметризированные запросы
  3. Пароли в виде открытого текста
52
ответ дан 3 revs, 2 users 88% 23 November 2019 в 03:53
поделиться

Мои проблемы являются таблицами 450 столбцов Access, которые были соединены 8-летним сыном грумера собаки лучших друзей исполнительного директора и изворотливой таблицы поиска, которая только существует, потому что кто-то не знает, как нормализовать datastructure правильно.

Как правило, эта таблица поиска похожа на это:

ID INT,
Name NVARCHAR(132),
IntValue1 INT,
IntValue2 INT,
CharValue1 NVARCHAR(255),
CharValue2 NVARCHAR(255),
Date1 DATETIME,
Date2 DATETIME

я потерял счет числу клиентов, которые я видел, у кого есть системы, которые полагаются на отвращение как это.

46
ответ дан 2 revs, 2 users 93% 23 November 2019 в 03:53
поделиться

Те, что мне не нравится большинство,

  1. Используя пробелы при составлении таблиц, sprocs и т.д. Все хорошо с CamelCase или under_scores и исключительный или множественные числа и ВЕРХНИЙ РЕГИСТР или нижний регистр, но имея необходимость относиться к таблице или столбцу [с пробелами], особенно если [это странно расположено с интервалами] (да, я столкнулся с этим) действительно раздражает меня.

  2. Денормализованные данные. Таблица не должна быть отлично нормализована, но когда я сталкиваюсь с таблицей сотрудников, которая имеет информацию об их текущем счете оценки или их основном устройстве что-либо, это говорит мне, что я должен буду, вероятно, сделать отдельную таблицу в какой-то момент и затем попытаться сохранить их синхронизировавшими. Я нормализую данные сначала и затем если я буду видеть место, где денормализация помогает, я рассмотрю его.

  3. Злоупотребление или представлениями или курсорами. Представления имеют цель, но когда каждая таблица обертывается в представление, это слишком много. Я должен был использовать курсоры несколько раз, но обычно можно использовать другие механизмы для этого.

  4. Доступ. Программа может быть антишаблоном? У нас есть SQL Server на моей работе, но много людей используют доступ из-за, он - доступность, "простота использования" и "дружелюбие" нетехническим пользователям. Существует слишком много здесь для входа, но если Вы были в аналогичной среде, Вы знаете.

28
ответ дан Jamal Hansen 23 November 2019 в 03:53
поделиться

используйте SP в качестве префикса имени процедуры хранилища, потому что это будет сначала искать в Системном месте процедур, а не пользовательских.

26
ответ дан 2 revs, 2 users 57% 23 November 2019 в 03:53
поделиться

Злоупотребление временными таблицами и курсорами.

25
ответ дан Rockcoder 23 November 2019 в 03:53
поделиться
  • FROM TableA, TableB WHERE синтаксис для СОЕДИНЕНИЙ, а не FROM TableA INNER JOIN TableB ON

  • предположения Создания, что запрос будет возвращен, отсортировали определенный путь, не вставляя пункт ORDER BY, просто потому что это было способом, которым это обнаружилось во время тестирования в инструментальном средстве формирования запросов.

17
ответ дан Joel Coehoorn 23 November 2019 в 03:53
поделиться
select some_column, ...
from some_table
group by some_column

и предполагая, что результат будет отсортирован по some_column. Я видел это немного с Sybase, где предположение содержит (на данный момент).

21
ответ дан Adrian Pronk 23 November 2019 в 03:53
поделиться

Я должен поместить своего собственного текущего фаворита здесь, только для вхождения в завершенный список. Мой любимый антишаблон не тестирование Ваших запросов .

Это применяется когда:

  1. Ваш запрос включает больше чем одну таблицу.
  2. Вы думаете, что имеете оптимальный дизайн для запроса, но не потрудились тестировать свои предположения.
  3. Вы принимаете первый запрос, который работает без подсказки о том, является ли это даже близко к оптимизированному.

И любой тестовый прогон против нетипичных или недостаточных данных не рассчитывают. Если это - хранимая процедура, поместило тестовый оператор в комментарий и сохраняет его с результатами. Иначе поместите его в комментарий в коде с результатами.

12
ответ дан 3 revs, 2 users 81% 23 November 2019 в 03:53
поделиться

использование @@ ИДЕНТИФИКАЦИОННЫЕ ДАННЫЕ вместо SCOPE_IDENTITY ()

Заключенный в кавычки из этого ответа:

  • @@ ИДЕНТИФИКАЦИОННЫЕ ДАННЫЕ возвращают последнее значение идентификационных данных, сгенерированное для любой таблицы на текущей сессии через все объемы. Необходимо быть осторожными здесь, так как это через объемы. Вы могли получить значение от триггера вместо Вашего текущего оператора.
  • SCOPE_IDENTITY возвращает последнее значение идентификационных данных, сгенерированное для любой таблицы на текущей сессии и текущей области. Обычно, что Вы хотите использовать.
  • IDENT_CURRENT возвращает последнее значение идентификационных данных, сгенерированное для определенной таблицы на любой сессии и любом объеме. Это позволяет Вам указать, от какой таблицы Вы хотите значение, в случае, если два выше не вполне, в чем Вы нуждаетесь (очень редкий). Вы могли использовать это, если Вы хотите получить текущее значение ИДЕНТИФИКАЦИОННЫХ ДАННЫХ для таблицы, в которую Вы не вставили запись.
23
ответ дан 3 revs 23 November 2019 в 03:53
поделиться
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

Или, собрав все в одну строку.

20
ответ дан 23 November 2019 в 03:53
поделиться

Общие ограничения используют «когда» в F #:

type Foo<'a when 'a :> IComparable> = 
  member x.Bla = 0
- 121 --- 3666100--

Для хранения значений времени следует использовать только часовой пояс UTC. Местное время не должно использоваться.

24
ответ дан 23 November 2019 в 03:53
поделиться

Злоупотребление временной таблицей.

В частности, такого рода вещи:

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)

Не создавайте временную таблицу из запроса, только для удаления ненужных строк.

И да, я видел страницы кода в этой форме в производственных БД.

10
ответ дан 23 November 2019 в 03:53
поделиться

Изучать SQL в первые шесть месяцев своей карьеры и никогда больше ничего не изучать в течение следующих 10 лет. В частности, отсутствие обучения или эффективного использования оконных / аналитических функций SQL. В частности, использование over () и partition by.

Оконные функции, как и агрегатные функции, выполняют агрегирование определенного набора (группы) строк, но вместо того, чтобы возвращать одно значение для каждого {{1} }, оконные функции могут возвращать несколько значений для каждой группы.

См. Приложение A «Поваренная книга SQL» O'Reilly для получения хорошего обзора оконных функций.

14
ответ дан 23 November 2019 в 03:53
поделиться

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!

23
ответ дан 23 November 2019 в 03:53
поделиться

Присоединение к избыточным таблицам в запрос как это:

select emp.empno, dept.deptno
from emp
join dept on dept.deptno = emp.deptno;
2
ответ дан Tony Andrews 23 November 2019 в 03:53
поделиться

Возможно, не анти-шаблон, но это раздражает меня, когда DBA определенного DB (хорошо я говорю о Oracle здесь) пишет использованию кода SQL Server стиль Oracle и кодирует соглашения и жалуется, когда это работает настолько плохо. Достаточно с курсорами люди Oracle! SQL предназначен, чтобы быть установленным базирующийся.

1
ответ дан Craig 23 November 2019 в 03:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: