Запрос с MIN (дата) не завершен за 20 часов: должен ли он быть таким, или я что-то не так сделал? - PullRequest
0 голосов
/ 24 сентября 2019

Вдохновленный постом Томмазо Пиффери , я создал базу данных PostgreSQL (11) для работы с данными временных рядов: 316 тыс. Финансовых инструментов, всего 139 млн записей.Временные ряды разных инструментов различаются по длине и временным периодам и часто имеют разрывы.Есть две таблицы: описание приборов и данные записей временных рядов.Структура очень проста:

  • TABLE instruments имеет

    • instr_id INT PRIMARY KEY и
    • еще 9 столбцов, описывающих каждый инструмент,
  • TABLE timeseries имеет

    • PRIMARY KEY (instr_id, date), где

    • instr_id INT REFERENCES instruments(instr_id) связывает времязаписи серии с описанием прибора,

    • date DATE NOT NULL - это дата записи временного ряда

      Нет индекса для date.

    • еще 5 столбцов, содержащих такие показатели, как цена, объем торгов и т. Д.

Я работаю в Python 3.7, использую psycopg2 в качестве драйвера и sqlalchemyкак ORM (но это, вероятно, не имеет значения).Сначала я заполнил базу данных с использованием DataFrame.to_sql, запустил VACUUM и проверил, что простые запросы работают правильно.Затем я хотел добавить в таблицу instruments несколько столбцов, обобщающих свойства временных рядов.Вот первый запрос, который я выполнил, используя cursor.execute(), чтобы проверить эту идею.Предполагается найти для каждого временного ряда дату самой ранней записи времени:

ALTER TABLE instruments
    ADD begin DATE; 
UPDATE instruments SET
    begin = (
        SELECT MIN(date) FROM timeseries
        WHERE timeseries.instr_id=instruments.instr_id
            );

Этот запрос выполнялся на настольном ПК (Intel i5, 8 ГБ памяти, Windows 7) около 20часов без результата.Активность сервера, отображаемая в pgAdmin 4, выглядит следующим образом.

Я новичок в реляционных базах данных и SQL.Это нормально, что такой запрос выполняется так долго, или я делаю что-то не так?

enter image description here

Ответы [ 3 ]

3 голосов
/ 24 сентября 2019

Подобные обновления обычно выполняются быстрее, если вы объединяете один раз все и включаете это в оператор UPDATE:

UPDATE instruments 
  SET "begin" = t.start_date
FROM (
  SELECT instr_id, MIN(date) 
  FROM timeseries
  group by instr_id
) t
WHERE t.instr_id = instruments.instr_id;
3 голосов
/ 24 сентября 2019

Ответ от a_horse_with_no_name является правильным, но если вы хотите ускорить запрос, не переписывая его, вам следует

CREATE INDEX ON timeseries (date);

Это ускорит повторный отбор и, следовательно, весь запрос значительно.

2 голосов
/ 24 сентября 2019

Что нужно сделать, чтобы получить MIN(date)?Что ж, нужно отсканировать целую таблицу из 139 миллионов записей ... Для каждого инструмента - и это объяснение.

Чтобы увидеть, как выполняется запрос, используйте explain - здесь Вы можете найти документацию.Обратите внимание, что использование explain analyze может занять эти 5 часов, так как запрос должен быть выполнен для сбора всей информации.

Что делать?Вы можете создать индекс.Вопрос в том, будет ли это работать.PG будет использовать индекс, если запрос выбирает менее 2% таблицы.В других случаях это будет идти с seqscan - чтение всей таблицы.Если вы чувствуете, что seqscan - ваш случай, вы можете рассмотреть возможность добавления даты в индекс - таким образом, вместо чтения таблицы БД может использовать статистику этого индекса.Чтобы проверить - используйте объяснение.

Это общий ответ.Просто попробуйте поиграть с этим.Если у вас есть еще вопросы, мы можем попытаться составить окончательный ответ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...