Находить данные, наиболее близкие к дате?

0

У меня есть таблица

CREATE TABLE `symbol_details` (
  `symbol_header_id` int(11) DEFAULT NULL,
  `DATE` datetime DEFAULT NULL,
  `ADJ_NAV` double DEFAULT NULL
)

с ~ 20 000 000 записей. Теперь я хочу найти значение ADJ_NAV ближе всего к концу четверти всего за один символ_header_id:

SET @quarterend = '2009-3-31';

SELECT  symbol_header_id AS she, ADJ_NAV AS aend FROM symbol_details
WHERE
 symbol_header_id = 18546 
 AND DATE= (
# date closest after quarter end
SELECT DATE FROM symbol_details
WHERE ABS(DATEDIFF(DATE, @quarterend)) < 10
AND DATE<=@quarterend
AND symbol_header_id = 18546 
ORDER BY  ABS(DATEDIFF(DATE, @quarterend)) ASC LIMIT 1)

Когда я запускаю внутренний запрос "выбрать дату", он быстро возвращается. Просто запуск внешнего запроса с нужной датой, заполненной вместо подзапроса, также заканчивается очень быстро. Но когда я управляю всем этим, это берет навсегда - что-то не так?

  • 0
    У вас есть индекс на дату, а также symbol_header_id?
  • 0
    Я делаю. Один на дату и один на symbol_header_id и дату плюс один на symbol_header_id. Меняет ли это способ оценки запроса?
Теги:
select
datediff

3 ответа

2

Кажется, что у оптимизатора есть некоторые проблемы, чтобы правильно оценить утверждение и найти наиболее эффективный план. (В Oracle я бы попросил вас обновить статистику, но я не уверен, как оптимизатор работает в MySQL.)

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

  • явно подключить два символа_header_ids объекта immer и внешнего запроса
  • попробуйте SELECT max(date) .. вместо "Order By Limit 1"
  • попытайтесь сделать самостоятельное присоединение к символам_описания

Надеюсь, здесь есть полезная идея.

1

Возможно, вы можете обойтись без подзапроса. Просто возьмите первую строку:

SELECT *
FROM symbol_details
WHERE DATE <= @quarterend
AND symbol_header_id = 18546
ORDER BY DATE DESC
LIMIT 1
  • 0
    Это правда, но тогда проблема в том, что если нет данных за этот квартал, он вернет действительно старые данные. Но я мог бы просто добавить И дата> @quarterstart ... Позвольте мне попробовать это. Большое спасибо за ответ!!
  • 0
    Это замечательно и привело меня к решению, см. Мою напыщенную речь в продолжающемся оригинальном сообщении, но мне пришлось изменить это на группу, чтобы получить все значения. Но теперь есть другая проблема ...
Показать ещё 1 комментарий
1

Try:

   SELECT t.symbol_header_id,
          COALESCE(t.adj_nav, '0.0') 'adj_nav'
     FROM SYMBOL_DETAILS t
LEFT JOIN (SELECT sh.symbol_header_id,
                  MAX(sh.date) 'max_date'
             FROM SYMBOL_DETAILS sh
            WHERE ABS(DATEDIFF(sh.date, @quarter_end)) < 10
              AND sh.date <= @quarter_end) x ON x.symbol_header_id = t.symbol_header_id
                                            AND x.max_date = t.date
   WHERE t.symbol_header_id = 18546

Ещё вопросы

Сообщество Overcoder
Наверх
Меню