Оптимизировать запрос с несколькими объединениями в одной таблице - PullRequest
0 голосов
/ 24 сентября 2019

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

Я должен объединить их с учетом производственной партии (столбец DAT и такой же, как AR1ID) и сгруппировать их по среднему значению каждого значения (толщина, вес, ширина, длина)

Это полный запрос со всеми соединениями:

SELECT p1.AR1ID as 'Article', p1.DAT as 'Lot', ROUND((SUM(p1.VAL))/(COUNT(p1.VAL)),2) as 'Weight', ROUND((SUM(p2.VAL))/(COUNT(p2.VAL)),2) as 'Width', ROUND((SUM(p3.VAL))/(COUNT(p3.VAL)),2) as 'Length', ROUND((SUM(p4.VAL))/(COUNT(p4.VAL)),2) as 'Thickness'
From( PesoMedioLotto  p1 JOIN PesoMedioLotto  p2 on p1.AR1ID = p2.AR1ID and p1.DAT = p2.DAT)
    join PesoMedioLotto p3 on p2.AR1ID = p3.AR1ID and p2.DAT = p3.DAT
    join PesoMedioLotto p4 on p3.AR1ID = p4.AR1ID and p3.DAT = p4.DAT
    Where p1.DES1 = 'Weight' and p2.des1 = 'Width' and p3.DES1='Length' and p4.DES1 = 'Thickness'
Group by p1.AR1ID, p1.DAT

Как видите, я использую AR1ID, чтобы объединение было одинаковым для всех

... и sql загружается

Но если я используюэтот запрос (объединяя только p1 и p2) у меня правильные результаты:

Запрос:

SELECT p1.AR1ID as 'Article', p1.DAT as 'Lot', ROUND((SUM(p1.VAL))/(COUNT(p1.VAL)),2) as 'Weight', ROUND((SUM(p2.VAL))/(COUNT(p2.VAL)),2) as 'Width'
From( PesoMedioLotto  p1 JOIN PesoMedioLotto  p2 on p1.AR1ID = p2.AR1ID and p1.DAT = p2.DAT)
    Where p1.DES1 = 'Weight' and p2.des1 = 'Width'
Group by p1.AR1ID, p1.DAT 

И отлично работает после 20 секунд загрузки ..!

Этоэто результаты:

<table>
  <tr>
    <th>Article</th>
    <th>Lot</th>
    <th>Weight</th>
    <th>Width</th>
  </tr>
  <tr>
    <td>1010585</td>
    <td>20190910</td>
    <td>7,85</td>
    <td>43,54</td>
  </tr>
  <tr>
    <td>1010500</td>
    <td>20190718</td>
    <td>18,51</td>
    <td>67,4</td>
  </tr>
  <tr>
    <td>1010444</td>
    <td>20190502</td>
    <td>19,6</td>
    <td>68,17</td>
  </tr>
  <tr>
    <td>1010314</td>
    <td>20190427</td>
    <td>9,09</td>
    <td>42,96</td>
  </tr>
  <tr>
    <td>1010525</td>
    <td>20190505</td>
    <td>19,43</td>
    <td>66,92</td>
  </tr>
  <tr>
    <td>1010397</td>
    <td>20190729</td>
    <td>3,02</td>
    <td>30,38</td>
  </tr>
  <tr>
    <td>1010387</td>
    <td>20190806</td>
    <td>18,74</td>
    <td>66,78</td>
  </tr>
</table>

Есть идеи?Спасибо !!

1 Ответ

2 голосов
/ 24 сентября 2019

Таким образом, ваш запрос в основном сводится к (я думаю):

SELECT
    p1.AR1ID AS Article,
    p1.DAT AS Lot,
    ROUND((SUM(p1.VAL))/(COUNT(p1.VAL)),2) AS [Weight],
    ROUND((SUM(p2.VAL))/(COUNT(p2.VAL)),2) AS [Width],
    ROUND((SUM(p3.VAL))/(COUNT(p3.VAL)),2) AS [Length],
    ROUND((SUM(p4.VAL))/(COUNT(p4.VAL)),2) AS [Thickness]
FROM
    PesoMedioLotto p1
    INNER JOIN PesoMedioLotto p2 ON p2.AR1ID = p1.AR1ID AND p2.DAT = p1.DAT AND p2.DES1 = 'Width'
    INNER JOIN PesoMedioLotto p3 ON p3.AR1ID = p1.AR1ID AND p3.DAT = p1.DAT AND p3.DES1 = 'Length'
    INNER JOIN PesoMedioLotto p4 ON p4.AR1ID = p1.AR1ID AND p4.DAT = p1.DAT AND p4.DES1 = 'Thickness'
WHERE 
    p1.DES1 = 'Weight'
GROUP BY
    p1.AR1ID,
    p1.DAT;

Мне было бы интересно посмотреть, что произойдет, когда вы запустите это:

SELECT DISTINCT
    p1.AR1ID AS Article,
    p1.DAT AS Lot
FROM
    PesoMedioLotto p1
    INNER JOIN PesoMedioLotto p2 ON p2.AR1ID = p1.AR1ID AND p2.DAT = p1.DAT AND p2.DES1 = 'Width'
    INNER JOIN PesoMedioLotto p3 ON p3.AR1ID = p1.AR1ID AND p3.DAT = p1.DAT AND p3.DES1 = 'Length'
    INNER JOIN PesoMedioLotto p4 ON p4.AR1ID = p1.AR1ID AND p4.DAT = p1.DAT AND p4.DES1 = 'Thickness'
WHERE 
    p1.DES1 = 'Weight';

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

Я предполагаю, что у вас в базе данных гораздо больше данных о длине и / или толщине, чем о весах или ширинах?

Это также может быть полезно длязнать:

SELECT DES1, COUNT(*) AS freq FROM PesoMedioLotto GROUP BY DES1;

Тогда мои следующие вопросы будут:

  • Почему все эти данные находятся в одной таблице, когда может иметь смысл иметь разные таблицы для разных метрик?
  • содержит ли данные строки для других значений DES1, и если да, то сколько?
  • есть ли сироты, например, толщина для AR1ID / DAT, который также не имеет веса?
  • у вас есть хорошие индексы для этой таблицы?

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

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

Может быть что-то вроде этого:

SELECT AR1ID, DAT, DES1, VAL INTO #temp FROM PesoMedioLotto WHERE DES1 IN ('Weight', 'Width', 'Length', 'Thickness');
CREATE INDEX ix$lotto1 ON #temp (DES1);
CREATE INDEX ix$lotto2 ON #temp (AR1ID, DAT);

SELECT
    p1.AR1ID AS Article,
    p1.DAT AS Lot,
    ROUND((SUM(p1.VAL))/(COUNT(p1.VAL)),2) AS [Weight],
    ROUND((SUM(p2.VAL))/(COUNT(p2.VAL)),2) AS [Width],
    ROUND((SUM(p3.VAL))/(COUNT(p3.VAL)),2) AS [Length],
    ROUND((SUM(p4.VAL))/(COUNT(p4.VAL)),2) AS [Thickness]
FROM
    #temp p1
    INNER JOIN #temp p2 ON p2.AR1ID = p1.AR1ID AND p2.DAT = p1.DAT AND p2.DES1 = 'Width'
    INNER JOIN #temp p3 ON p3.AR1ID = p1.AR1ID AND p3.DAT = p1.DAT AND p3.DES1 = 'Length'
    INNER JOIN #temp p4 ON p4.AR1ID = p1.AR1ID AND p4.DAT = p1.DAT AND p4.DES1 = 'Thickness'
WHERE 
    p1.DES1 = 'Weight'
GROUP BY
    p1.AR1ID,
    p1.DAT;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...