Sql Join на пользовательские функции: как оптимизировать - PullRequest
0 голосов
/ 01 марта 2012

Я пытаюсь оптимизировать запрос в базе данных. Этот запрос похож на следующий:

select * from Account 
   inner join udf_Account('user') udfAccount 
   on Account.Id = udfAccount.AccountId

На самом деле реальный запрос намного длиннее, но наиболее важным моментом является то, что он содержит несколько внутренних объединений пользовательских функций (udf), которые зависят от идентификатора пользователя. (То есть это постоянный параметр, который не изменяется во время оценки запроса).

Из-за большого объема данных мой запрос занимает приблизительно 20 секунд в производственной базе данных, что недопустимо.

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

Я задаю следующие вопросы:

  1. Могу ли я избежать временных таблиц. Разве это не способ сказать sql, что функция может быть оценена только один раз? Использование временных таблиц повлекло бы за собой некоторые важные изменения в моем коде, поэтому я был бы рад, если бы у меня было другое решение.

  2. Есть ли другие способы оптимизировать мой запрос?

Ответы [ 2 ]

4 голосов
/ 01 марта 2012

В SQL Server, если ваши функции Inline, а не Multi-Statement, SQL Server выделяет tham (подобный макросу) в ваши запросы. Как будто они становятся подзапросами в вашем основном запросе.

Это условно позволяет оптимизатору составить «лучший» план выполнения.

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

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

(Это все немного упрощенно, но это хорошее начало для оптимизации запросов, что является огромной темой.)


Другой вариант - рассмотреть возможность использования CROSS APPLY со встроенными табличными функциями.
(Доступно в SQL Server 2005 и далее)

Это позволяет использовать значения из таблиц в ваших запросах в качестве параметров ваших функций. Опять же, при условии, что функции встроены, SQL Server расширяет встроенную функцию при построении плана выполнения.

Примером может быть ...

SELECT
  Account.AccountID,
  subAccount.AccountID        AS SubAccountID,
  Balance.currentAvailable    AS SubAccountBalance
FROM
  Account
CROSS APPLY
  dbo.getSubAccounts('User', Account.AccountID) AS SubAccount
CROSS APPLY
  dbo.getCurrentBalance(SubAccount.AccountID)   AS Balance
WHERE
  Account.AccountID = 1234
1 голос
/ 01 марта 2012

Полагаю, вы хотите определить, что mysql называет «детерминированной» функцией. В зависимости от вашего вида SQL это будет иметь другой синтаксис. Но в конечном итоге самой большой оптимизацией было бы вообще не использовать функцию, а просто добавить столбец учетной записи в таблицу пользователей.

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