Наилучшая практика для предложений where =?, Where в (?) В подготовленных выражениях? - PullRequest
3 голосов
/ 25 февраля 2010

Является ли более целесообразным использовать Подготовленное утверждение с одним вопросительным знаком в нем пятьдесят раз или использовать Подготовленное утверждение с пятидесяти вопросительными знаками в нем один раз?

По существу, Where Person = ? или Where Person IN (?, ?, ?, ...) лучше?

Пример

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

Принимая во внимание список из 1000 стран, как лучше всего получить население?

Имейте в виду, что это гипотетический пример, В Википедии число стран равняется 223 , давайте предположим, что для этого примера оно намного больше. Создайте оператор, который принимает параметр страны и возвращает население. Пример: Where Country = ?

Создать подготовленную выписку динамически, добавив? для каждого страна, использующая предложение Where in (?,?,etc). Пример: Where Country = (?, ?, ...)

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

Какой метод предпочтительнее?

Ответы [ 6 ]

5 голосов
/ 08 марта 2010

Я достиг точки в своем проекте, где смог протестировать некоторые реальные данные.

На основе 1435 элементов вариант 1 занимает ~ 8 минут, вариант 2 - ~ 15 секунд, а вариант 3 - ~ 3 минуты.

Вариант 2 - явный победитель с точки зрения производительности. Код немного сложнее, но разница в производительности слишком велика, чтобы ее игнорировать.

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

0 голосов
/ 08 марта 2010

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

Например, для MS SQL вы можете использовать функцию CSV-> Table, например: http://www.nigelrivett.net/SQLTsql/ParseCSVString.html

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

SELECT ..
FROM  table t
INNER JOIN dbo.fn_ParseCSVString(?, ',') x
     ON  x.s = t.id
WHERE ...

В этом случае будет два цикла: построение строки CSV (если у вас ее еще нет в этом формате) и разбиение CSV на таблицу.

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

Результаты также могут различаться в зависимости от нагрузки на сеть и т. Д. *

0 голосов
/ 07 марта 2010

Как уже говорили другие, это зависит от количества параметров и размера данных.Исходя из того, что вы указали в комментариях, исходная таблица может содержать сотни тысяч строк.Если это так, вопрос сводится к количеству разрешенных входов фильтрации.Будет ли ваш запрос только для небольшого набора входных данных, или он должен разрешить фильтрацию для тысячи стран?Если позже, то я бы порекомендовал сохранить выборки в промежуточную таблицу и объединить ее.Что-то вроде:

Create Table CriteriaSelections
(
    SessionOrUsername nvarchar(50) not null
    , Country nvarchar(50) not null
)

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

Select ...
From BigFatCountryTable
    Join CriteriaSelections
        On CriteriaSelections.Country = BigFatCountryTable.Country
            And CriteriaSelections.SessionOrUsername = @SessionOrUsername

Вы можете использовать RNGCryptoServiceProvider для генерации случайного числа, если этовызывается несколько раз по-разному одним и тем же «сеансом» параллельно.Подвох в этой настройке заключается в том, что вам необходимо периодически очищать таблицу выбора.

Если рассматриваемые сущности несколько неизменны (например, Страна, Город и т. Д.), То использование стратегии кэширования в сочетании с вашей стратегией запросов также поможет.

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

0 голосов
/ 06 марта 2010

Выполнение запроса выполняется в два этапа:
1. Создайте план выполнения.
2. Выполните план.

Подготовленные операторы относятся к шагу 1. В данном примере я думаю, что наибольшее время выполнения будет на шаге 2, поэтому я бы выбрал альтернативу, которая дает наилучшее выполнение. Общее правило, позволяющее оптимизировать механизм работы с БД, - задавать ему диапазон вопросов, а не зацикливать на клиенте, выдавая несколько небольших вопросов. Доступные индексы и задержка клиент-сервер, конечно, влияют на то, насколько велика разница, но я думаю, что ваш вариант №2 для динамического создания подготовленного оператора является лучшей альтернативой.

Вы провели какие-нибудь тесты различных альтернатив? Если у вас есть, что они показывают?

0 голосов
/ 02 марта 2010

ОЗУ дешево. Загрузить весь список в кешированную таблицу и работать со скоростью памяти

Если производительность является проблемой, используйте RAM. Вы могли бы потратить дни или недели, пытаясь оптимизировать что-то, что могло бы уместиться в 100 $ оперативной памяти

0 голосов
/ 25 февраля 2010

Как часто говорят: «Это зависит». Если вы просто ищете население одной страны, я бы выбрал метод 1. Я бы избегал # 2, потому что я не люблю использовать динамически построенный SQL, если только это не единственный способ выполнить работу ( эффективно), и это, кажется, не один из тех случаев. Я тоже не большой в №3, потому что я думаю, что цикл будет неэффективным, если вам нужно собрать население всех стран.

Как насчет добавления # 4: единственное утверждение, которое возвращает население всех стран, что-то вроде

SELECT C.COUNTRY_NAME, SUM(S.POPULATION)
  FROM COUNTRY C,
       COUNTRY_CENSUS_SUBDIVISION S
  WHERE S.ID_COUNTRY = C.ID_COUNTRY
  GROUP BY C.COUNTRY_NAME;

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

Делись и наслаждайся.

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