Оптимизировать запрос в SQL Server - PullRequest
0 голосов
/ 24 ноября 2011

У меня есть запрос в Sql Server, который я хотел бы оптимизировать.

SELECT user_type_name = CASE user_type_id 
                          WHEN 1 THEN 'Admin' 
                          WHEN 5 THEN 'Super Admin' 
                          WHEN 3 THEN 'Writer' 
                          WHEN 4 THEN 'Reader' 
                        END, 
       user_can_log = CASE user_inactive 
                        WHEN 1 THEN 'No' 
                        ELSE 'Yes' 
                      END, 
       (SELECT COUNT(*) 
        FROM   t_fthread 
        WHERE  fthread_creator_userid = user_id)         AS number_tickets, 
       (SELECT COUNT(*) 
        FROM   t_email 
        WHERE  email_to LIKE '%' + user_email + '%' 
                OR email_cc LIKE '%' + user_email + '%') AS number_emails, 
       * 
FROM   t_user 
       LEFT JOIN t_organisation 
         ON user_org_id = organisation_id 
WHERE  user_org_id = 42 
ORDER  BY user_last_name, 
          user_first_name 

Выполнение запроса занимает слишком много времени.Благодаря анализатору запросов, я определил часть запроса, которая занимает слишком много времени. Вот этот раздел:

(select count(*) from t_email where email_to like '%'+user_email+'%' or email_cc like '%'+user_email+'%') as number_emails.

Я пытаюсь переписать запрос, чтобы получить число_почт, но в каждом случаеЭто все еще очень медленно.

Я пытался создать индексы, но невозможно создать индексы для user_email и user_cc.Оба столбца относятся к типу ntext, и на сервере sql 2000 невозможно создать индекс для этих столбцов.Я запустил анализ запроса с помощью помощника по настройке ядра СУБД и выполнил рекомендации, предоставленные инструментами.

CREATE NONCLUSTERED INDEX [_dta_index_t_fthread_15_2073058421__K5] ON [dbo].[t_fthread]
(
[fthread_creator_userid] ASC
)

CREATE STATISTICS [_dta_stat_1365579903_4_3] ON [dbo].[t_user]([user_last_name], [user_first_name])

CREATE STATISTICS [_dta_stat_1365579903_1_5] ON [dbo].[t_user]([user_id], [user_org_id])

CREATE NONCLUSTERED INDEX [_dta_index_t_user_15_1365579903__K5_K1] ON [dbo].[t_user]
(
[user_org_id] ASC,
[user_id] ASC
)

Но запрос все еще занимает много времени, чтобы завершить выполнение.

Ответы [ 4 ]

3 голосов
/ 24 ноября 2011

Ваш запрос указывает на плохой дизайн.Вам следует либо

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

Нормализуйте вашу базу данных

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

Вместо хранения писем в to и cc, создавайте новые таблицы и сохраняйте идентификаторы электронной почты, а также идентификаторы пользователя от to и cc.

Отслеживайте количество отправленных электронных писем

Добавьте два столбца (Number_To, Number_CC) в t_userтаблицы и увеличивайте их по мере необходимости (при отправке электронных писем, сохраняя их в t_email таблице, ...).Если вы решили пойти по этому пути, следите за параллелизмом, лучше всего сделать UPDATE t_user SET Number_To = Number_To + 1 вместо того, чтобы выбрать текущее значение Number_To и затем обновить его до нового значения.

0 голосов
/ 24 ноября 2011

Попробуйте этот запрос один раз. Также попробуйте = оператор вместо LIKE

SELECT tu.*,

(case when  user_type_id = 1 then 'Admin' 
       when user_type_id = 5 then 'Super Admin' 
       when user_type_id = 3 then 'Writer' 
       when user_type_id = 4 then  'Reader'
       else 'somethingelse' 
       end) as user_type_name, 

    (case when user_inactive = 1 then 'No'
     else 'Yes' end) as user_can_log,

    (select count(*) as number_tickets from  t_fthread where
    fthread_creator_userid=user_id()),

    (select count(*) as number_emails from  t_email where email_to like '%abc@xyz.com%'
  or email_cc like '%abc@xyz.com%') 

   FROM t_user tu left join t_organisation torg on tu.user_org_id=
  torg.organisation_id   where tu.user_org_id = 42  order by tu.user_last_name, 
  tu.user_first_name 
0 голосов
/ 24 ноября 2011

Ну, вы можете сделать следующее для электронной почты:

    SELECT COUNT(*) 
    FROM   t_email 
    WHERE  
       (
            PATINDEX('%' + user_email + '%', email_to) != 0
            OR PATINDEX('%' + user_email + '%', email_cc) != 0
       )
0 голосов
/ 24 ноября 2011

Можно ли выполнить поиск, используя:

 email_to like user_email+'%' 

или даже закодировать все альтернативы? Или, что еще лучше, храните электронную почту пользователя (которую нужно искать позже) в «очищенной» форме в базе данных?

Подстановочный знак перед user_email является злым: текстовый поиск, начинающийся с '%', всегда будет медленным, потому что он непредсказуем, и вы никогда не узнаете, где в строке будет найден текст поиска.

Например, рассмотрим текст:

kakaka@mailblahblah.youknowka@this.text

Хотя это относительно небольшая строка, поиск текста "ka@this.text" будет выглядеть следующим образом

  • "k" найдено на первой позиции
  • матч все еще на второй позиции
  • несоответствие на третьей позиции

это продолжается два раза, и в третий раз '' @ '' найден. Тогда несоответствие в четвертой позиции.

Только после примерно 36 операций сравнения SQL Server узнает совпадения строк. И это только для одной строки. Поэтому старайтесь избегать подстановочных знаков в начале сравнения строк.

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