Лучший шаблон для констант в SQL? - PullRequest
9 голосов
/ 30 июля 2010

Я видел несколько шаблонов, используемых для «преодоления» недостатка констант в SQL Server, но ни один из них, по-видимому, не удовлетворяет требованиям как производительности, так и удобочитаемости / удобства обслуживания.

В приведенном ниже примере предполагается, что мыУ нас есть целая классификация «статус» в нашей таблице, варианты выглядят так:

  • Просто для жесткого кодирования и, возможно, просто «комментируем» статус

-- StatusId 87 = Loaded
SELECT ... FROM [Table] WHERE StatusId = 87;
  • Использование таблицы поиска для состояний, а затем присоединение к этой таблице, так что предложение WHERE ссылается на понятное имя.

SubQuery:

SELECT ... 
FROM [Table] 
WHERE 
  StatusId = (SELECT StatusId FROM TableStatus WHERE StatusName = 'Loaded');

или объединенный

SELECT ... 
FROM [Table] t INNER JOIN TableStatus ts On t.StatusId = ts.StatusId 
WHERE ts.StatusName = 'Loaded';
  • Определен набор скалярных UDF, которые возвращают константы, а именно

CREATE Function LoadedStatus()
RETURNS INT
AS
 BEGIN
  RETURN 87
 END;

, а затем

SELECT ... FROM [Table] WHERE StatusId = LoadedStatus();

(IMO это вызывает сильное загрязнение базы данных - это может быть нормально в оболочке пакета Oracle)

  • И аналогичные шаблоны с табличными функциями, содержащими константысо значениями в виде строк или столбцов, которые CROSS APPLIED возвращаются к [Table]

Как другие пользователи SO решили эту распространенную проблему?

Edit : Баунти - У кого-нибудь есть лучший метод для поддержания $ (переменных) в сценариях DBProj DDL / Schema согласно ответу и комментарию Remus?

Ответы [ 4 ]

12 голосов
/ 30 июля 2010

жестко закодировано.С производительностью SQL важнее ремонтопригодность.

Последствия в плане выполнения между использованием константы, которую оптимизатор может проверить во время генерации плана, и использованием любой формы косвенного обращения (UDF, JOIN, подзапрос) часто бывают драматичными.SQL-компиляция - это необычный процесс (в том смысле, что он не является "обычным", как, скажем, генерация IL-кода), поскольку результат определяется не только компилируемой языковой конструкцией (т. Е. Фактическим текстом запроса), но ипо схеме данных (существующие индексы) и фактические данные в этих индексах (статистика).Когда используется жестко закодированное значение, оптимизатор может дать лучший план, потому что он может фактически сравнить значение со статистикой индекса и получить оценку результата.

Другое соображение состоит в том, что приложение SQL не является кодомтолько, но с большим отрывом это код и данных.«Рефакторинг» SQL-программы ... отличается.Там, где в программе на C # можно изменить константу или перечисление, перекомпилировать и успешно запустить приложение, в SQL этого нельзя сделать, поскольку это значение, вероятно, присутствует в миллионах записей в базе данных, а изменение значения константы подразумевает также изменение ГБ данных.часто онлайн при выполнении новых операций.

То, что значение жестко задано в запросах и процедурах, видимых сервером, не обязательно означает, что значение должно быть жестко задано воригинальный исходный код проекта.Существуют различные инструменты генерации кода, которые могут позаботиться об этом.Рассмотрим что-нибудь столь же тривиальное, как использование переменных сценариев sqlcmd :

defines.sql:

:setvar STATUS_LOADED 87

somesource.sql:

:r defines.sql
SELECT ... FROM [Table] WHERE StatusId = $(STATUS_LOADED);

someothersource.sql:

:r defines.sql
UPDATE [Table] SET StatusId = $(STATUS_LOADED) WHERE ...;
6 голосов
/ 06 августа 2010

Хотя я согласен с Ремусом Русану, IMO, удобство сопровождения кода (и, следовательно, удобочитаемость, наименьшее изумление и т. Д.) Превосходит другие проблемы, если разница в производительности не является достаточно значительной, чтобы оправдать действия по-другому.Таким образом, следующий запрос теряет читабельность:

Select ..
From Table
Where StatusId = 87

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

Таким образом, моя таблица «Status» будет выглядеть следующим образом:

Create Table Status
(
    Code varchar(6) Not Null Primary Key
    , ...
)
Select ...
From Table
Where StatusCode = 'Loaded'

Это делает запрос более читабельным, не требует объединения в таблицу Status и не требует использованиямагического числа (или гида).Использование пользовательских функций IMO - плохая практика.Помимо влияния на производительность, ни один разработчик не ожидал бы, что UDF будут использоваться таким образом, и таким образом нарушает критерии наименьшего удивления.Вы бы почти были вынуждены иметь UDF для каждой константы value ;иначе, что вы передаете в функцию: имя?волшебная ценность?Если имя, вы можете также сохранить имя в таблице и использовать его непосредственно в запросе.Если магическое значение, вы вернулись к исходной проблеме.

3 голосов
/ 30 июля 2010

Я использовал опцию скалярной функции в нашей БД, и она отлично работает, и, на мой взгляд, лучший способ этого решения.

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

2 голосов
/ 05 августа 2010

Вы также можете добавить дополнительные поля в вашу таблицу состояния, которые действуют как уникальные маркеры или группировщики для значений состояния.Например, если вы добавите поле isLoaded в таблицу состояния, запись 87 может быть единственной с установленным значением поля, и вы можете проверить значение поля isLoaded вместо жестко заданного 87 или описания состояния.

...