Реализация функции поиска с несколькими необязательными параметрами для таблицы базы данных - PullRequest
8 голосов
/ 06 мая 2010

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

Целевой платформой является.Net с бэкэндом SQL 2005, 2008, но я думаю, что это довольно общая проблема.

Например, у нас есть таблица клиентов, и мы хотим предоставить пользовательскому интерфейсу функцию поиска для различных параметров, таких как тип клиента, состояние клиента, почтовый индекс клиента и т. д., и все они являются необязательными и могут быть выбраны в любых комбинациях.Другими словами, пользователь может выполнять поиск только по customerType или customerType, customerZIp или любым другим возможным комбинациям.Существует несколько доступных подходов к проектированию, но все они имеют некоторые недостатки, и я хотел бы спросить, есть ли среди них предпочтительный дизайн или есть другой подход.

  1. Создайте оператор sql where claus sql динамически на бизнес-уровне на основе запроса поиска из пользовательского интерфейса и передайте его хранимой процедуре в качестве параметра.Что-то вроде @Where = ', где CustomerZip = 111111' Внутри хранимой процедуры сгенерируйте динамический SQL-оператор и выполните его с помощью sp_executesql.Недостаток: динамический sql, sql инъекция

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

ГДЕ

        (CustomerType = @CustomerType OR @CustomerType is null )

AND      (CustomerZip = @CustomerZip OR @CustomerZip is null )

AND   …………………………………………

Недостаток: возможная проблема с производительностью для sql.

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

Ответы [ 4 ]

4 голосов
/ 06 мая 2010

Это лучшая статья, описывающая тонкие последствия для производительности того, как сделать это в SQL: Условия динамического поиска в T-SQL Эрланда Соммарского . Он охватывает каждый метод и подробно описывает все «за» и «против» каждого метода.

2 голосов
/ 06 мая 2010

Я опубликовал это как комментарий, но понял, что это, вероятно, ответ.

Писать предикаты как WHERE @Param IS NULL OR Column = @Param нехорошо, потому что оптимизатор обычно считает, что это не sargable.

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

DECLARE @PrimaryKey int
SET @PrimaryKey = 1

SELECT CoveredColumn
FROM Table
WHERE @PrimaryKey IS NULL
OR PrimaryKeyColumn = @PrimaryKey

SELECT CoveredColumn
FROM Table
WHERE PrimaryKeyColumn >= ISNULL(@PrimaryKey, 0)
AND PrimaryKeyColumn <= ISNULL(@PrimaryKey, 2147483647)

Оба эти оператора SELECT будут давать идентичные результаты, предполагая, что столбец PK является неотрицательным int. Но для этого выберите план выполнения, и вы увидите огромную разницу в стоимости. Первый SELECT выполняет полное сканирование индекса и обычно занимает около 90% стоимости запроса.

Если вы хотите иметь необязательные условия поиска в SQL и не можете использовать динамический SQL, лучше для производительности, если вместо этого вы можете превратить его в запрос диапазона вместо ISNULL. Даже если диапазон равен огромный (буквально половина диапазона int здесь), оптимизатор все равно выяснит это, если используется необязательный параметр .

2 голосов
/ 06 мая 2010

Метод 1: динамический SQL может принимать параметры, это довольно тривиально и практически исключает риск внедрения SQL. Лучший аргумент против динамического SQL - то, как нетривиальным операторам может потребоваться сложная логика для генерации, хотя это также не проблема, если вы используете приличный ORM.

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

Метод 2: Я лично использовал метод два в прошлом без проблем. Вы прокомментировали «возможную проблему производительности для SQL», но профилировали ли вы? Сравнивали планы выполнения? По моему собственному опыту, при использовании подхода @param is null OR col = @param их производительность практически не снизилась. Помните, что если на оптимизацию кода у вас уходит 10 часов времени разработчика, чтобы сэкономить 10 микросекунд в год, ваша чистая экономия по-прежнему составляет почти -10 часов.

Метод 3: Комбинаторный взрыв. Избегайте любой ценой.

2 голосов
/ 06 мая 2010
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...