2015-07-14 3 views
0

Я извлекаю (только для чтения) информацию из базы данных, имеющей пару тысяч строк в двух разных таблицах, один с 5 столбцами и один с тремя столбцами. Вот мой код:SQL: мой очень короткий код времени; REGR_SLOPE очень медленный

SELECT DISTINCT q1.MACHINE_ID, q1.SIGNAL_ID, ROUND(86400000*(REGR_SLOPE(ts.VALUE, ts.EPOCH) OVER (PARTITION BY ts.MACHINE_SIGNAL_ID))) AS RATE, q1.LAST_VALUE 

FROM TSD_SUB ts, 

(SELECT ms.MACHINE_SIGNAL_ID, ms.LAST_TIMESTAMP FROM MACHINE_SIGNAL ms 
    WHERE (ms.MACHINE_ID LIKE 'CV%' OR ms.MACHINE_ID LIKE 'MT%') 
    AND (ms.SIGNAL_ID = ANY('WFRCOUNT','WFRCNTR') OR ms.SIGNAL_ID LIKE '%WAFERCT%')) q1 

WHERE ts.MACHINE_SIGNAL_ID = q1.MACHINE_SIGNAL_ID 
    AND ts.EPOCH > (q1.LAST_TIMESTAMP - 604800000) 

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

SELECT * FROM MACHINE_SIGNAL 
     WHERE (MACHINE_ID LIKE 'CV%' OR MACHINE_ID LIKE 'MT%') 
     AND (SIGNAL_ID = ANY('WFRCOUNT','WFRCNTR') OR SIGNAL_ID LIKE '%WAFERCT%') 

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

Эта база данных является базой данных Oracle, поэтому работа REGR_SLOPE отлично работает. Кроме того, если я просто пытаюсь запустить внешний код немного в то время, он отлично работает:

SELECT DISTINCT ROUND(86400000*(REGR_SLOPE(ts.VALUE, ts.EPOCH) OVER (PARTITION BY ts.MACHINE_SIGNAL_ID))) AS RATE 

FROM tsd_sub ts 

WHERE ts.machine_signal_id = '366625' -- taken from MACHINE_SIGNAL_ID of the first row of the previous code 
    AND ts.epoch > (1436855226000 - 604800000) -- from LAST_TIMESTAMP of the first row from the previous code 

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

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

Благодарим вас за внимание и помощь!


EDIT:

Таблица MACHINE_SIGNAL имеет переменную MACHINE_SIGNAL_ID, которая появляется только один раз в MACHINE_SIGNAL, но появляется много раз в TSD_SUB. Поэтому я просто пытаюсь вычислить REGR_SLOPE из нескольких строк в TSD_SUB, чтобы соответствовать одной строке в MACHINE_SIGNAL. Но да, я не могу просто присоединиться к таблицам, потому что TSD_SUB имеет слишком много строк для каждого значения MACHINE_SIGNAL_ID в MACHINE_SIGNAL.


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

SELECT MACHINE_SIGNAL_ID, 
     ROUND(86400000*(REGR_SLOPE(ts.VALUE, ts.EPOCH))) AS RATE 

FROM TSD_SUB ts, 

    (SELECT DISTINCT (Max(ts0.EPOCH) - 604800000) AS YESTERDAY 
    FROM TSD_SUB ts0 
    WHERE ROWNUM < 100) ts1 

WHERE ts.EPOCH > ts1.YESTERDAY 

GROUP BY MACHINE_SIGNAL_ID 

Это означает, что присоединение его MACHINE_SIGNAL не будет работать вообще, если я не могу также ограничить значениями MACHINE_SIGNAL_ID, которые я смотрю для MACHINE_SIGNAL, но я не могу искать эти значения, не глядя сначала на MACHINE_SIGNAL. Это похоже на проблему catch-22.


Следующий код действительно работает, поэтому HURRAY благодарит всех вас за помощь.

SELECT ms.MACHINE_ID, ms.SIGNAL_ID, ms.MACHINE_SIGNAL_ID, ms.Last_Value, ts.EPOCH, ts.VALUE 

FROM MACHINE_SIGNAL ms JOIN 
    (SELECT ts.MACHINE_SIGNAL_ID, ts.EPOCH, ts.VALUE FROM TSD_SUB ts, 
        (SELECT (Max(ts0.EPOCH) - 604800000) AS YESTERDAY 
        FROM TSD_SUB ts0 
        WHERE ROWNUM < 1000) ts1 
       WHERE ts.EPOCH > ts1.YESTERDAY) ts 
    on ts.machine_signal_id = ms.machine_signal_id 

WHERE (ms.MACHINE_ID LIKE 'CV%' OR ms.MACHINE_ID LIKE 'MT%') AND 
     (ms.SIGNAL_ID IN ('WFRCOUNT', 'WFRCNTR') OR SIGNAL_ID LIKE '%WAFERCT%') 

Теперь моя задача выяснить, как получить REGR_SLOPE от этой новой таблицы на каждый MACHINE_SIGNAL_ID, а не получать его из всей таблицы. Возможно, это новая проблема, поэтому я вернусь к вам.


Да по какой-то причине, даже если код выше соединения таблиц работает, окружающий бит вычисления REGR_SLOPE еще таймаут. Ниже приведен полный код с частями, которые работают с комментариями.

SELECT myTable.MACHINE_ID, 
     myTable.SIGNAL_ID, 
     ROUND(86400000*REGR_SLOPE(myTable.VALUE, myTable.EPOCH)) AS RATE, 
     myTable.Last_Value 

FROM 
-- THIS PART WORKS PERFECTLY WELL -- 
(SELECT ms.MACHINE_ID, ms.SIGNAL_ID, ms.MACHINE_SIGNAL_ID, ms.Last_Value, ts.EPOCH, ts.VALUE 

FROM MACHINE_SIGNAL ms JOIN 
    (SELECT ts.MACHINE_SIGNAL_ID, ts.EPOCH, ts.VALUE FROM TSD_SUB ts, 
        (SELECT (Max(ts0.EPOCH) - 604800000) AS YESTERDAY 
        FROM TSD_SUB ts0 
        WHERE ROWNUM < 1000) ts1 
       WHERE ts.EPOCH > ts1.YESTERDAY) ts 
    on ts.machine_signal_id = ms.machine_signal_id 

WHERE (ms.MACHINE_ID LIKE 'CV%' OR ms.MACHINE_ID LIKE 'MT%') AND 
     (ms.SIGNAL_ID IN ('WFRCOUNT', 'WFRCNTR') OR SIGNAL_ID LIKE '%WAFERCT%')) myTable 
-- UP TO HERE IS A VALID TABLE WHICH RUNS IN LESS THAN A SECOND -- 

Group BY myTable.MACHINE_SIGNAL_ID, myTable.MACHINE_ID, myTable.SIGNAL_ID, myTable.Last_Value 

Единственное, что вещества, которые здесь добавляются являются REGR_SLOPE и GROUP BY, но даже когда REGR_SLOPE имеет PARTITION внутри него (как у меня было в начале) это еще раз из. Это означает, что функция REGR_SLOPE просто делает что-то, чего я не ожидаю, потому что это происходит очень медленно. Если он проходит через каждую строку, как мне заставить его остановиться, а если нет, то почему это так медленно?

Спасибо!

ответ

0

Я не знаю, поможет ли это, но, возможно, более удобная запись вашего запроса поможет оптимизатору. Я предполагаю, что это эквивалентно запросу:

SELECT ms.MACHINE_ID, ms.SIGNAL_ID, 
     ROUND(86400000*(REGR_SLOPE(ts.VALUE, ts.EPOCH))) AS RATE, 
     ms.LAST_VALUE 
FROM MACHINE_SIGNAL JOIN 
    tsd_sub ts 
    on ts.machine_signal_id = ms.machine_signal_id 
WHERE (ms.MACHINE_ID LIKE 'CV%' OR ms.MACHINE_ID LIKE 'MT%') AND 
     (ms.SIGNAL_ID IN ('WFRCOUNT', 'WFRCNTR') OR SIGNAL_ID LIKE '%WAFERCT%') AND 
     ts.epoch > (q1.LAST_TIMESTAMP - 604800000) 
GROUP BY ms.MACHINE_ID, ms.SIGNAL_ID, ms.LAST_VALUE; 

Это предполагает, что signal_id является определение machine_id и last_value. Он заменяет аналитическую функцию функцией агрегации.

Ваша версия запроса выполняет регрессию для каждой строки, созданной соединением , а затем делает отчетливую. Просто используйте group by.

0

Краткость кода не имеет ничего общего с производительностью. На самом деле более длинный код в SQl часто является лучшим выбором.

Я уверен, что у Oracle есть эквивалент плана выполнения SQL Server или mysql explainplan. Вам нужно найти, что это такое, и запустить его, чтобы увидеть, что вызывает замедление.

Я не знаю ничего о производительности Oracle, поскольку он очень отличается от того, что делает запросы медленными в SQl-сервере, но вы захотите посмотреть, выполняете ли вы сканирование таблицы или используете indexxes. Вы захотите посмотреть, сколько читаемых таблиц.

Я знаю, что вы делаете некоторые проблемы, связанные с производительностью в большинстве баз данных. Сначала вы используете только один столбец в производной таблице, поэтому не используйте select *. Это антиспам SQL в почти всех базах данных. Разумеется, конечно, делает вещи медленнее, но не всегда нужно избегать.

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

Одна вещь, которую я мог бы рассмотреть пытается это заменить этот код:

DISTINCT q1.MACHINE_ID, q1.SIGNAL_ID, ROUND(86400000*(REGR_SLOPE(ts.VALUE, ts.EPOCH) 

Вместо писать производную таблицу, которая получает отчетливое q1.MACHINE_ID, q1.SIGNAL_ID, ts.VALUE, ts.EPOCH, а затем сделать вычисление только активирует ваши отдельные строки. Сейчас он выполняет функцию против всех строк, прежде чем сможет сделать отдельную часть.

0

Сначала подумайте, для каких данных необходимо вычислить наклон регрессии. На основе вашего предложения PARTITION BY это MACHINE_SIGNAL_ID.

Поместите этот столбец (ы) в GROUP BY Не использовать аналитическую функцию (PARTITION BY) и DISTINCT

Начать с запросом, как этот

SELECT MACHINE_SIGNAL_ID, 
    ROUND(86400000*(REGR_SLOPE(ts.VALUE, ts.EPOCH))) AS RATE 
FROM TSD_SUB ts 
WHERE .. add filter predicated to limit records 
GROUP BY MACHINE_SIGNAL_ID 

Регистрация результат с другими таблицами если вам нужна дополнительная информация.