Запрос скорости вставки / обновления SMA (простая скользящая средняя) - PullRequest
1 голос
/ 17 апреля 2020

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

У меня есть следующая таблица:

CREATE TABLE `timeseries_test` (
 `timeseries_id` int(11) NOT NULL AUTO_INCREMENT,
 `stock_id` int(10) NOT NULL,
 `date` date NOT NULL,
 `open` decimal(16,8) NOT NULL,
 `high` decimal(16,8) NOT NULL,
 `low` decimal(16,8) NOT NULL,
 `close` decimal(16,8) NOT NULL,
 `adjusted_close` double(16,8) NOT NULL,
 `volume` int(16) NOT NULL,
 `dividend` double(16,8) NOT NULL,
 `split_coefficient` double(16,15) NOT NULL,
 `100sma` decimal(16,8) NOT NULL,
 PRIMARY KEY (`timeseries_id`),
 KEY `stock` (`stock_id`),
 KEY `date` (`date`),
 KEY `date_stock` (`stock_id`,`date`)
) ENGINE=InnoDB AUTO_INCREMENT=5444325 DEFAULT CHARSET=latin1

Я пробовал много разных форматов запросов, но все они занимают около 25 секунд на 5000 строк. Запрос на выбор занимает менее секунды. Ниже пример запроса:

UPDATE stock.timeseries_test t1 INNER JOIN (
SELECT a.timeseries_id,
       Round( ( SELECT SUM(b.close) / COUNT(b.close)
                FROM timeseries_test AS b
                WHERE DATEDIFF(a.date, b.date) BETWEEN 0 AND 99 AND a.stock_id = b.stock_id
              ), 2 ) AS '100sma'
     FROM timeseries_test AS a) t2

ON t1.`timeseries_id` = t2.`timeseries_id`
SET t1.100sma = t2.100SMA
WHERE t2.100sma = null

Ниже запроса объяснения:

1   PRIMARY <derived2>  NULL    ALL NULL    NULL    NULL    NULL    10385   10.00   Using where 
1   UPDATE  t1  NULL    eq_ref  PRIMARY PRIMARY 4   t2.timeseries_id    1   100.00  NULL    
2   DERIVED a   NULL    index   NULL    date_stock  7   NULL    10385   100.00  Using index 
3   DEPENDENT SUBQUERY  b   NULL    ref stock,date_stock    stock   4   stock.a.stock_id    5192    100.00  Using where 

Любая помощь приветствуется.

Ответы [ 2 ]

1 голос
/ 17 апреля 2020

Если вы используете MySQL 8.0, я рекомендую оконные функции со спецификацией range; это устраняет необходимость в коррелированном подзапросе.

update stock.timeseries_test t1 
inner join (
    select timeseries_id,
    avg(close) over(
        partition by stock_id 
        order by date 
        range between interval 99 day preceding and current row
    ) `100sma`
    from timeseries_test
) t2 on t1.timeseries_id = t2.timeseries_id
set t1.`100sma` = t2.`100sma`

Совершенно неясно, какова цель оригинального, внешнего where предложения, поэтому я удалил его:

WHERE t2.`100sma` = null

Если вы хотите проверить null ness, тогда вам нужно is null; но это в значительной степени победило бы всю логику c оператора update Может быть, вы имели в виду:

WHERE t1.`100sma` is null
0 голосов
/ 18 апреля 2020

Функции не допускаются. Вместо

DATEDIFF(a.date, b.date) BETWEEN 0 AND 99

используйте

a.date BETWEEN b.date AND b.date + INTERVAL 99 DAY

(или, возможно, a и b следует поменять местами)

Я подозреваю (из имен столбцов), что пара (stock_id, date) уникальна, и timeseries_id никогда не используется. Если они верны, то

PRIMARY KEY (`timeseries_id`),
KEY `date_stock` (`stock_id`,`date`)

->

PRIMARY KEY(`stock_id`,`date`)

Необходимо изменить ON(timestamp_id для проверки обоих этих столбцов.

Также, бросьте это, так как есть другой индекс, который начинается с того же столбца (столбцов):

KEY `stock` (`stock_id`),
...