#mysql #sql
Вопрос:
время | ценность |
---|---|
00:00 | 100 |
00:01 | 101 |
00:02 | 102 |
01:03 | 103 |
02:04 | 104 |
03:05 | 105 |
03:10 | 106 |
Скажем, у меня есть таблица mysql с указанной выше структурой, индексированной по столбцу времени.
Как я могу получить первую строку непосредственно перед определенной меткой времени. Например, я должен быть в состоянии прочитать строку [02:04 : 104], если я хочу получить метку времени до 02:30.
Кроме того, поскольку время не увеличивается последовательно, я не могу получить, просто уменьшившись на одну минуту.
Один из известных мне способов-упорядочить строки по убыванию и ограничить на 1, но, похоже, это выполняет сканирование диапазона индексов, которое будет дорогостоящим по мере увеличения числа строк. Есть ли какой-либо способ получить значение в виде операции с постоянным временем?
Комментарии:
1. Пожалуйста, предоставьте достаточно кода, чтобы другие могли лучше понять или воспроизвести проблему.
Ответ №1:
Вы можете использовать LIMIT
запрос:
SELECT time, value
FROM yourTable
WHERE time < '02:30'
ORDER BY time DESC
LIMIT 1;
Для приведенного выше запроса может быть полезен следующий индекс:
CREATE INDEX idx ON yourTable (time, value);
Это должно позволить MySQL быстро найти интересующую запись в логарифмическом времени и вернуть ее. Индекс также охватывает value
столбец, так что это можно назвать индексом покрытия.
Комментарии:
1. Да, но проблема в том, что, похоже, он выполняет сканирование всех строк до 02:30, а затем возвращает первую строку после спуска. Это будет довольно интенсивно, если в таблице много строк.
2. @VikrantPradhan Такого АФАЙКА не избежать. Проверьте мой обновленный ответ на наличие опции индекса.
Ответ №2:
Я не думаю, что вы сможете сделать это за постоянное время. Я считаю , что вы должны создать предыдущий момент времени с помощью LAG
, добавить индекс, а затем отфильтровать с WHERE
помощью оператора. Из любопытства и поскольку у вас есть индекс time
, выполняется ли это быстрее, чем LIMIT
запрос?
WITH cte AS (
SELECT time,
value,
LAG(time) OVER(ORDER by time) AS prev_time
FROM input_table
-- Try to add a WHERE statement here to limit the number of rows selected (since you have an index on time). That would make things faster of course.
)
SELECT *
FROM cte
WHERE '02:30' BETWEEN prev_time and time