Mysql запрос головоломки - поиск того, что было бы самой последней датой
Вопрос
Я посмотрел все и еще не нашел интеллектуальный способ справиться с этим, хотя я уверен, что можно:
Одна таблица исторических данных имеет ежеквартальную информацию:
CREATE TABLE Quarterly (
unique_ID INT UNSIGNED NOT NULL,
date_posted DATE NOT NULL,
datasource TINYINT UNSIGNED NOT NULL,
data FLOAT NOT NULL,
PRIMARY KEY (unique_ID));
Еще одна таблица исторических данных (которая очень большая) содержит ежедневная информация:
CREATE TABLE Daily (
unique_ID INT UNSIGNED NOT NULL,
date_posted DATE NOT NULL,
datasource TINYINT UNSIGNED NOT NULL,
data FLOAT NOT NULL,
qtr_ID INT UNSIGNED,
PRIMARY KEY (unique_ID));
Поле QTR_ID не является частью подачи ежедневных данных, которые населены базы данных - вместо этого мне нужно обратное обратное заполнение поля Qtr_id в ежедневной таблице с quartlyly.unique_id id ряд ряд, используя, как было бы самые последние ежеквартальные данные что daily.date_posted для этого источника данных.
Например, если ежеквартальные данные
101 2009-03-31 1 4.5
102 2009-06-30 1 4.4
103 2009-03-31 2 7.6
104 2009-06-30 2 7.7
105 2009-09-30 1 4.7
и ежедневные данные
1001 2009-07-14 1 3.5 ??
1002 2009-07-15 1 3.4 &&
1003 2009-07-14 2 2.3 ^^
Тогда мы хотели бы ?? Поле Qtr_id должно быть назначено «102» как последний квартал для этого источника данных в этой дате, и && также будет «102», а ^^ будет «104».
Проблемы включают в себя, что обе таблицы (особенно ежедневные таблицы) на самом деле очень велики, их нельзя нормализовать, чтобы избавиться от повторяющихся дат или иным образом оптимизированных, и для определенных ежедневных записей нет предшествующих квартальной записи.
Я пробовал множество присоединений, используя Dateiff (где вызов находит минимальное значение Dateiff, больше нуля), а для меня другие попытки, но ничего не работает - обычно мой синтаксис где-то ломается где-то. Любые идеи приветствуют - я выполню любые основные идеи или концепции и доклад.
Решение
Просто подзапрос на ID четверти, используя что-то вроде:
(
SELECT unique_ID
FROM Quarterly
WHERE
datasource = ?
AND date_posted >= ?
ORDER BY
unique_ID ASC
LIMIT 1
)
Конечно, это, вероятно, не даст вам наилучшую производительность, и она предполагает, что даты добавляются в квартал последовательно (в противном случае order by date_posted
). Тем не менее, это должно решить вашу проблему.
Вы бы использовали этот подзапрос на вашем INSERT
или UPDATE
заявления как стоимость вашего qtr_ID
поле для вашего Daily
стол.
Другие советы
Следующее, по-видимому, работает точно так же, как предназначено, но это, безусловно, является уродливым (с тремя вызовами к одному и тому же Dateiff !!), возможно, увидев рабочий запрос, кто-то может быть в состоянии дальше уменьшить его или улучшить:
UPDATE Daily SET qtr_ID = (select unique_ID from Quarterly
WHERE Quarterly.datasource = Daily.datasource AND
DATEDIFF(Daily.date_posted, Quarterly.date_posted) =
(SELECT MIN(DATEDIFF(Daily.date_posted, Quarterly.date_posted)) from Quarterly
WHERE Quarterly.datasource = Daily.datasource AND
DATEDIFF(Daily.date_posted, Quarterly.date_posted) > 0));
После получения дополнительной работы над этим запросом я оказался огромным улучшением производительности над оригинальной концепцией. Наиболее важным улучшением было создание индексов как в ежедневных, так и ежеквартальных таблицах - в ежедневной основе я создал индексы (DataSource, Date_Posted) и (DataSource, DataSource), используя BTREE и ON (DataSource), используя хеш, а в квартал я сделал то же самое предмет. Это излишки, но он убедился, что у меня был вариант, который может использовать двигатель запроса. Это уменьшило время запроса до менее чем 1% от того, что было. (!!)
Затем я узнал, что учитывая мои особые обстоятельства, которые я мог бы использовать Max () вместо порядка и ограничить, поэтому я использую вызов на MAX (), чтобы получить соответствующий Unique_id. Это уменьшило время запроса примерно на 20%.
Наконец, я узнал, что с механизмом хранения InnoDB я мог бы сегментировать кусок ежедневного стола, который я обновил с любым запросом, который позволил мне многорезать запросы с небольшим количеством локтя и сценариев. Параллельная обработка работала хорошо, и каждая нить снизила время линейно.
Итак, основной запрос, который выполняет буквально в 1000 раз лучше, чем моя первая попытка:
UPDATE Daily
SET qtr_ID =
(
SELECT MAX(unique_ID)
FROM Quarterly
WHERE Daily.datasource = Quarterly.datasource AND
Daily.date_posted > Quarterly.dateposted
)
WHERE unique_ID > ScriptVarLowerBound AND
unique_ID <= ScriptVarHigherBound
;