2013-04-05 5 views
0

У меня есть таблицы с несколькими миллионами строк и нужно получить последние строки конкретных идентификаторовКак я могу принести последние N строк, не заказывая таблицу

, например, последнюю строку, которая device_id = 123 и последний строка, которая имеет device_id = 1234

, потому что таблицы настолько огромны, и упорядочение занимает так много времени, возможно ли выбрать последний 200 без заказа таблицы, а затем просто заказать эти 200 и получить нужные мне строки.

Как бы я это сделал?

Заранее благодарю вас за помощь!

UPDATE

Мой PostgreSQL версии 9.2.1

выборка данных:

time      device_id   data  data .... 
"2013-03-23 03:58:00-04" | "001EC60018E36" | 66819.59 | 4.203 
"2013-03-23 03:59:00-04" | "001EC60018E37" | 64277.22 | 4.234 
"2013-03-23 03:59:00-04" | "001EC60018E23" | 46841.75 | 2.141 
"2013-03-23 04:00:00-04" | "001EC60018E21" | 69697.38 | 4.906 
"2013-03-23 04:00:00-04" | "001EC600192524"| 69452.69 | 2.844 
"2013-03-23 04:01:00-04" | "001EC60018E21" | 69697.47 | 5.156 
.... 

См SQLFiddle of this data

Так что если device_id = 001EC60018E21 Я хотел бы самым последним строка с этим device_id. Это грантополучатель, что последняя строка с этим device_id - это строка, которую я хочу, но она может быть или не быть последней строкой таблицы.

+0

последние 200 строк гарантированно иметь последние строки, где идентификатор = 123 и идентификатор = 1234 –

+0

Если вы знаете идентификаторы, почему бы вы потрудились выборки всю таблицу? Стратегически расположенный индекс RDBMS решит проблему просто отлично. – dasblinkenlight

+0

Всегда лучше показывать версию PostgreSQL, образцы данных и ожидаемые результаты, поэтому нам не нужно создавать тестовые примеры для вас. –

ответ

1

Общий способ получения «последней» строки для каждого device_id выглядит следующим образом.

select * 
from Table1 
inner join (select device_id, max(time) max_time 
      from Table1 
      group by device_id) T2 
    on Table1.device_id = T2.device_id 
    and Table1.time = T2.max_time; 

Получение «последнего» 200 device_id номера без использования ORDER BY не очень практично, но это не ясно, почему вы можете захотеть сделать это в первую очередь. Если 200 - произвольное число, то вы можете получить лучшую производительность, взяв подмножество таблицы, основанную на произвольном времени.

select * 
from Table1 
inner join (select device_id, max(time) max_time 
      from Table1 
      where time > '2013-03-23 12:03' 
      group by device_id) T2 
on Table1.device_id = T2.device_id 
and Table1.time = T2.max_time; 
+0

Смешное время, тот же запрос в течение минуты друг друга, редактирование одновременно –

+0

@CraigRinger: Эй, если я пишу тот же SQL, что и вы, я помещаю это в свое резюме. –

+0

Спасибо Майку Шеррилю «Катколл» и Крейгу Рингеру! Мне нужно немного времени, чтобы переварить блестящие идеи, и да 200 было произвольным числом, и вы правы, что произвольные данные лучше. –

2

Лично я бы создать составной индекс на device_id и нисходящих time:

CREATE INDEX table1_deviceid_time ON table1("device_id","time" DESC); 

, то я хотел бы использовать подзапрос, чтобы найти самый высокий time для каждого device_id и присоединиться результаты подзапроса к основной таблице на device_id и time найти соответствующие данные, например:

SELECT t1."device_id", t1."time", t1."data", t1."data1" 
FROM Table1 t1 
INNER JOIN (
    SELECT t1b."device_id", max(t1b."time") FROM Table1 t1b GROUP BY t1b."device_id" 
) last_ids("device_id","time") 
ON (t1."device_id" = last_ids."device_id" 
    AND t1."time" = last_ids."time"); 

См this SQLFiddle.

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

BTW, time - ужасное имя для столбца, потому что это встроенное имя типа данных. Используйте что-то более подходящее, если сможете.

+0

Это может прийти к тому моменту, когда мне нужно это сделать. И «время» как имя не может быть изменено, уже слишком много зависимых скриптов, но я буду помнить об этом. Спасибо за помощь! –

Смежные вопросы