Как я могу получить верхние записи X для каждого отдельного столбца в пределах каждого диапазона временной отметки Y, для некоторого другого столбца Z?

0

До сих пор я использую много маленьких запросов в цикле для достижения этого. Я надеюсь, что есть способ сконцентрировать это на одном запросе, так как эти запросы начинают отсчитывать часы до конца (миллионы строк), причем некоторые ожидаемые тесты требуют в двадцать раз больше данных. Есть ли способ написать запрос, который получает 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>
Теги:

1 ответ

0

Прежде всего, убедитесь, что у вас есть ключ 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

  • 0
    Но фильтрация на стороне клиента - это именно то, чего я пытаюсь избежать. Кроме того, есть первичный ключ, я чувствовал, что это был шум для данных примера.
  • 0
    Разместите ваши точные запросы и расположение клавиш. На данный момент я подозреваю, что фильтрация на стороне клиента - это не то, что вас убивает, а большое количество запросов без ключа. Эта проблема потенциально может быть решена без фильтрации на стороне клиента, но это потребует некоторой работы - см. Мою схему решения UDF. Тем не менее, я считаю, что вы можете добиться приличной производительности с помощью фильтрации на стороне клиента, если у вас есть правильные ключи в таблице. Ключи имеют решающее значение. Не попадайтесь в ловушку, что если у вас есть какой-то ключ, запрос будет быстрым. Ключ должен быть адаптирован для запроса.

Ещё вопросы

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