2010-07-30 6 views
8

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

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

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

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

подзапрос:

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'; 
  • кучу определенных констант, которые возвращают скалярной ОДС, а именно

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

, а затем

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

(ИМО это вызывает большое загрязнение в базе данных - это может быть хорошо в пакете оберткой Oracle)

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

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

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

ответ

11

Жесткий код. С поддержкой производительности кодов SQL.

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

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

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

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 ...; 
+0

Спасибо - мы используем DBPRO, и это привело меня к http://blogs.msdn.com/b/gertd/archive/2007/01/08/variables-to-the-rescue.aspx – StuartLC

+0

К сожалению, DBPRO не принять подстановку $ (variable) в * каждый * исходный .sql-файл, только в файлах сценария .sql (сценарий запускается после развертывания схемы). Было бы здорово, если бы вы могли использовать переменные в определении процедур ... –

+0

Спасибо Remus - если мы сможем обойти это ограничение, это было бы идеальным решением IMHO. Я добавил щедрость;) – StuartLC

3

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

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

2

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

+0

Привет Бет, спасибо за ответ - интересный, определенно действительный образец удобочитаемости. Итак, я бы добавил в битовые поля для каждого состояния IsLoaded, IsCancelled, IsSomeOtherStatus , и тогда каждое состояние будет иметь только соответствующий бит. Я предполагаю, что недостатком является то, что дополнительное присоединение к статусу необходимо для достижения удобочитаемости. – StuartLC

+0

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

6

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

Select .. 
From Table 
Where StatusId = 87 

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

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

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

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

+0

Yup, имеет смысл, однако «наименьший int» PK является стандартом проектирования БД в нашей компании (стандартный суррогат против естественного аргумент ключей уже разыгран в пользу суррогатов). Наши DBA похожи на узкие индексы, и столбцы, подобные статусу, сильно фильтруются в запросах. – StuartLC

+0

@nonnb - Наличие стандартного стандартного ключа от внешних ключей и суррогатных ключей ложно предполагает, что одно и только одно решение имеет смысл для всех таблиц. Это похоже на то, чтобы все двери имели одну ручку, даже двойные двери или двери, которые не нуждаются в ручке. Оба типа ключей имеют свое место. Использование суррогатных ключей для валют, например, было бы плохим дизайнерским решением IMO. Это добавит ненужных объединений и поможет прочитать код. Короче говоря, это будет стоить компании деньги. Код состояния одного символа будет по-прежнему лучше магического числа и займет то же пространство, что и tinyint. – Thomas

+0

вы проповедуете преобразованному. Я провел год, поддерживая DB Pick/Universe не так давно, и преимущества кодирования «внешних ключей» (не то, что у U2 были), и, таким образом, экономия на соединении вообще была кристально чистой :) – StuartLC