Загадка MySQL запроса - поиск того, что было бы самой последней датой - PullRequest
2 голосов
/ 15 мая 2010

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

Одна таблица исторических данных содержит квартальную информацию:

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 в таблице Daily идентификатором строки Quarterly.unique_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».

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

Я пробовал различные объединения, используя datediff (где задача состоит в том, чтобы найти минимальное значение datediff больше нуля) и другие попытки, но у меня ничего не работает - обычно мой синтаксис где-то нарушается. Любые идеи приветствуются - я выполню любые основные идеи или концепции и сообщу.

Ответы [ 3 ]

1 голос
/ 15 мая 2010

Просто подзапрос для идентификатора квартала, используя что-то вроде:

(
 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.

0 голосов
/ 01 июня 2010

После дополнительной работы над этим запросом я получил огромное улучшение производительности по сравнению с первоначальной концепцией. Наиболее важным улучшением было создание индексов в таблицах Daily и Quarterly - в Daily я создавал индексы для (datasource, date_posted) и (date_posted, datasource) USING BTREE и для (datasource) USING HASH, а в Quarterly я делал то же самое вещь. Это излишне, но я убедился, что у меня есть опция, которую может использовать механизм запросов. Это сократило время запроса до менее чем 1% от того, что было. (!!)

Затем я узнал, что, учитывая мои конкретные обстоятельства, я могу использовать MAX () вместо ORDER BY и LIMIT, поэтому я использую вызов MAX (), чтобы получить соответствующий unique_ID. Это сократило время запроса примерно на 20%.

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

Итак, основной запрос, который выполняется буквально в 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
;
0 голосов
/ 18 мая 2010

Кажется, что следующее работает точно так, как задумано, но это, безусловно, некрасиво (с тремя вызовами одного и того же DATEDIFF !!), возможно, увидев рабочий запрос, кто-то сможет его уменьшить или улучшить:

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));
...