До сих пор я использую много маленьких запросов в цикле для достижения этого. Я надеюсь, что есть способ сконцентрировать это на одном запросе, так как эти запросы начинают отсчитывать часы до конца (миллионы строк), причем некоторые ожидаемые тесты требуют в двадцать раз больше данных. Есть ли способ написать запрос, который получает X количество записей различного device_id (столбца) для каждого временного шага Y для test_id Z?
С некоторыми примерами данных:
| ts | test_id | device_id | data | | 2018-06-25 06:00:00 | 0 | 1 | "blah00" | | 2018-06-25 08:00:00 | 1 | 1 | "blah01" | | 2018-06-25 08:00:00 | 1 | 2 | "blah02" | | 2018-06-25 08:00:02 | 1 | 1 | "blah03" | | 2018-06-25 08:00:02 | 1 | 2 | "blah04" | | 2018-06-25 08:00:05 | 1 | 1 | "blah05" | | 2018-06-25 08:00:05 | 1 | 2 | "blah06" | | 2018-06-25 08:00:08 | 1 | 1 | "blah07" | | 2018-06-25 08:00:08 | 1 | 2 | "blah08" | | 2018-06-25 08:00:10 | 1 | 1 | "blah09" | | 2018-06-25 08:00:10 | 1 | 2 | "blah10" | | 2018-06-25 08:00:12 | 1 | 1 | "blah11" | | 2018-06-25 08:00:12 | 1 | 2 | "blah12" | | 2018-06-25 08:00:15 | 1 | 1 | "blah13" | | 2018-06-25 08:00:18 | 1 | 1 | "blah14" | | 2018-06-25 08:00:20 | 1 | 1 | "blah15" | | 2018-06-25 08:00:20 | 1 | 2 | "blah16" |
И я хотел получить первые 3 записи за каждые 10 секунд для test_id 1, я бы хотел получить результат:
| ts | test_id | device_id | data | | 2018-06-25 08:00:00 | 1 | 1 | "blah01" | | 2018-06-25 08:00:00 | 1 | 2 | "blah02" | | 2018-06-25 08:00:02 | 1 | 1 | "blah03" | | 2018-06-25 08:00:02 | 1 | 2 | "blah04" | | 2018-06-25 08:00:05 | 1 | 1 | "blah05" | | 2018-06-25 08:00:05 | 1 | 2 | "blah06" | | 2018-06-25 08:00:10 | 1 | 1 | "blah09" | | 2018-06-25 08:00:10 | 1 | 2 | "blah10" | | 2018-06-25 08:00:12 | 1 | 1 | "blah11" | | 2018-06-25 08:00:12 | 1 | 2 | "blah12" | | 2018-06-25 08:00:15 | 1 | 1 | "blah13" | | 2018-06-25 08:00:20 | 1 | 1 | "blah15" | | 2018-06-25 08:00:20 | 1 | 2 | "blah16" |
Некоторые вещи, которые нельзя считать само собой разумеющимися, - это то, что устройство может не записываться в течение некоторого времени (таким образом, я не могу гарантировать, что каждое устройство будет иметь одинаковое количество строк за период времени (поскольку я попытался воспроизвести в примере данные), в том числе, когда все устройства приостановлены в течение некоторого времени (таким образом, было бы возможно, чтобы не иметь данных для одного или нескольких последовательных временных рамок).
Мои текущие запросы (и окружающий псевдокод) - угловые скобки указывают какое-то значение, которое будет установлено на применимое значение:
For each distinct device_id in test_id Z SELECT ts FROM data_log WHERE (test_id=<Z> AND device_id=<device_id>) ORDER BY ts LIMIT 1 Store as newest SELECT ts FROM data_log WHERE (test_id=<Z> AND device_id=<device_id>) ORDER BY ts LIMIT 1 Store as oldest For currentTime = newest; currentTime < oldest; currentTime += timestep Y SELECT * FROM data_log WHERE (test_id=<Z> AND device_id=<device_id> AND ts>=<currentTime>) ORDER BY ts LIMIT <X>
Прежде всего, убедитесь, что у вас есть ключ on (test_id, ts) - столбцы в этом порядке, важные. Тогда вы можете сделать
select * from t where test_id = 1 order by ts
и обрабатывать вывод на клиенте, отфильтровывая записи, которые вы не хотите. Это должно дать вам ОК, хотя и не звездную производительность, если для каждого идентификатора теста имеется менее 10 М записей.
Если вам нравится C++, и вы хотите повысить производительность, вы можете написать UDF. Есть несколько трюков, которые вам нужно будет сделать для этого. Используйте initid->ptr
выделяя память, чтобы использовать ее для сохранения вашего буфера. Затем в этой области памяти вы можете запомнить информацию о ранее просмотренных строках, которая позволит вам решить, следует ли включать или не включать текущую строку в результат. Тогда ваш запрос будет примерно таким:
select * from t where test_id = 1 and should_include_test(ts,device_id) order by ts