Повышение производительности SQL-запросов - PullRequest
0 голосов
/ 14 июля 2011

У меня есть две таблицы. В одной таблице мы вводим все типы моделей, каждая модель содержит около 100 строк. Во второй таблице приведены данные о продажах первого товара. Мне нужно получить такой результат:

Date           Model    Total(WE BOUGHT)   Sold
----------     -----    ----------------   ----
2011-01-21      M34R            300         200
2011-01-21      M71S            250          22

Мой запрос выглядит так:

select distinct
   CONVERT(varchar(10),x.Scantime,120) as ScanDate,
   x.ModelNumber,
   (  Select count(*)
      from micro_model z
      where
         z.ModelNumber=x.ModelNumber
         and CONVERT(varchar(10),z.scantime,101)
            = CONVERT(varchar(10),x.Scantime,101)
   ) as Total,
   (   select COUNT(*)
       from
          micro_Model m
          inner join micro_model_sold y on m.IDNO=y.IDNO
       where
          CONVERT(varchar(10),m.scantime,101)
             = CONVERT(varchar(10),x.Scantime,101)
          and x.ModelNumber=m.ModelNumber
   ) as Sold
from maxis.dbo.maxis_IMEI_Model x 
where
    CONVERT(varchar(10),x.scantime,101) between '01/01/2011' and '01/25/2011'

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

Ответы [ 2 ]

6 голосов
/ 14 июля 2011

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

SELECT
   DateAdd(Day, DateDiff(Day, 0, X.ScanTime), 0) ScanDate,
   X.ModelNumber,
   Coalesce(Z.Total, 0) Total,
   Coalesce(Z.Sold, 0) Sold
FROM
   maxis.dbo.maxis_IMEI_Model X
   LEFT JOIN (
      SELECT
         Z.ModelNumber,
         DateAdd(Day, DateDiff(Day, 0, Z.ScanTime), 0) ScanDate,
         Count(DISTINCT M.IDNO) Total,
         Count(Y.IDNO) Sold
      FROM
         micro_model Z
         LEFT JOIN micro_model_sold Y
            ON Z.IDNO = Y.IDNO
      GROUP BY
         DateDiff(Day, 0, Z.ScanTime),
         Z.ModelNumber
   ) Z
      ON X.ModelNumber = Z.ModelNumber
      AND X.ScanTime >= Z.ScanDate
      AND X.ScanTime < Z.ScanDate + 1
WHERE
   X.ScanTime >= '20110101'
   AND X.ScanTime < '20110126'
  1. Преобразование в символ для сравнения целых дат (путем отсечки символов, представляющих время) очень неэффективно.Лучшая практика - это делать, как я показал в предложении WHERE.Обратите внимание, что я увеличил окончательную дату на один день, а затем сделал эту точку исключительной , используя меньше чем вместо меньше или равно (что и делает BETWEEN).Все соединения также необходимо изменить.Наконец, когда необходимо , чтобы удалить временную часть даты, метод DateDiff, который я здесь показываю, является лучшим (есть немного более быстрый метод, который гораздо сложнее понять, поэтому я не могу его рекомендовать,но если вы используете SQL Server 2008, вы можете просто набрать Convert(date, DateColumn), что является самым быстрым из всех).

  2. Использование формата даты «01/01/2011» не является региономбезопасный.Если ваш запрос когда-либо использовался на компьютере, на котором язык был изменен на язык с форматом даты по умолчанию DMY, ваши даты будут интерпретироваться неправильно, меняя месяц и день и вызывая ошибки.Для обеспечения безопасности используйте формат yyyymmdd.

  3. Использование коррелированных подзапросов (ваши операторы SELECT в скобках для извлечения значений столбцов из других таблиц) неудобно и в некоторых случаях приводит к очень плохому выполнениюпланы.Несмотря на то, что оптимизатор часто может преобразовать их в правильные объединения, нет никакой гарантии.Другим людям, смотрящим на запрос, также становится очень трудно понять, что он делает.Лучше выразить такие вещи, используя внешние соединения, как показано.Я преобразовал коррелированные подзапросы в производные таблицы.

  4. Использование DISTINCT вызывает беспокойство.Ваш запрос не должен возвращать несколько строк для каждой модели.Если это так, то с запросом логически что-то не так, и вы, вероятно, получаете неверные данные.

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

  6. Я полностью переформатировал ваш запрос, потому что было почти невозможно увидеть, что он делает.Я рекомендую вам сделать немного больше форматирования в вашем собственном коде.Это поможет вам и всем, кто придет за вами, быстрее понять, что происходит.Если вы зададите больше вопросов по SQL на этом сайте, вам нужно лучше отформатировать собственный код.Пожалуйста, сделайте это, а также используйте кнопку «блок кода» или просто сделайте отступ всех строк кода на 4 пробела вручную, чтобы он был отформатирован веб-страницей как блок кода.

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

Возможно, проблемы в моем запросе могут быть решены с помощью простого GROUP BY и бросая несколько SUM s в числовые столбцы., но я не уверен на 100%.Может случиться так, что таблица maxis_IMEI_Model должна полностью исчезнуть или перейти в свою собственную производную таблицу, где она сгруппирована отдельно, прежде чем присоединиться.

2 голосов
/ 14 июля 2011

Я ни в коем случае не эксперт по SQL, но у вас есть лот конверсий. Зачем? Зачем вам нужно преобразовывать эти столбцы даты и времени (это тип, который я предполагаю для scantime и т. Д.) В строки перед их сравнением?

Я сильно подозреваю, что конверсии лишают вас никакой выгоды от того, какие индексы у вас есть. (У вас есть индексы для всех столбцов, участвующих в объединении, верно?) На самом деле, оба ваших объединения выглядят так, будто они должны быть объединениями по нескольким столбцам без каких-либо предложений where ... хотя я ожидаю, что оптимизатор запросов относиться к ним одинаково, если это возможно.

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

В целом - даже не только в SQL - всегда стоит пытаться работать с данными в их естественной форме, где это возможно. Вы имеете дело с датами / временем - так зачем рассматривать их как строки для сравнения? Преобразования являются источником проблем с производительностью и проблем с корректностью.

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