postgresql - мои индексы или типы столбцов замедляют мой запрос?

У меня есть таблица, которую я создал локально для использования некоторых оконных функций PG в наборе данных, содержащем около 4 миллионов строк (первоначально это был текстовый файл). Каждая строка соответствует заказу клиента.

CREATE TABLE orders
(
  orderid integer,
  customerid integer,
  orderdate date,
  status text,
  amount money,
  tax money,
  customername text,
  customerstate text

У меня есть база данных, работающая локально на машине i7 с 8 ГБ ОЗУ под управлением Windows 8. У меня есть индексы btree (индексы?) по идентификатору заказа, идентификатору клиента и дате заказа.

Когда я запускаю следующий запрос, это занимает 300 секунд (примерно). Я надеялся, что с некоторой базовой настройкой смогу сократить время до минуты, но я не администратор баз данных. У кого-нибудь есть советы?

select orderid, customername, orderdate, 
rank() OVER (PARTITION BY customername ORDER BY orderdate ASC) as cust_ord_nbr
from orders

person Jeffrey James    schedule 12.09.2015    source источник
comment
почему имя клиента в качестве ключа раздела, когда у вас есть идентификатор клиента в таблице?   -  person Daniel Vérité    schedule 12.09.2015
comment
@DanielVérité - теперь до 198 секунд :-)   -  person Jeffrey James    schedule 12.09.2015
comment
Сколько существует различных клиентов?   -  person wildplasser    schedule 12.09.2015
comment
@wildplasser — 3,3 миллиона   -  person Jeffrey James    schedule 12.09.2015
comment
В этом случае нормализация клиентов в отдельной таблице не поможет (много). Единственное, что могло бы помочь, - это составной индекс (customerid, orderdate)   -  person wildplasser    schedule 12.09.2015
comment
@wildplasser - спасибо, я сократил время до 140 секунд. Любопытно - скорость из-за моего железа? Далее, это процессор, оперативная память или что-то еще? Что, если бы у меня было хранилище данных в 10 раз больше — просто «подождите»?   -  person Jeffrey James    schedule 12.09.2015
comment
Возможно, только объем данных: примерно 4M * ~ 100 ~ = 400 МБ данных. Попробуйте добавить к команде префикс EXPLAIN ANALYZE, чтобы получить время, необходимое для запроса без вывода.   -  person wildplasser    schedule 12.09.2015
comment
Каков ваш вариант использования? Клиент-человек не был бы заинтересован в получении 4 млн. ряды сразу. Вы пишете на другой стол? Я не вижу никаких ограничений, можете ли вы предоставить точное определение таблицы (что вы получаете с \d orders в psql)?   -  person Erwin Brandstetter    schedule 13.09.2015
comment
@ErwinBrandstetter - не производственный вариант использования, в основном подготовка к аудиту данных перед дальнейшим преобразованием и анализом.   -  person Jeffrey James    schedule 13.09.2015
comment
Какие столбцы вам нужны в результате? Вам нужен customername или customerid тоже подойдет? Куда отправить результат? Вы не просто запрашиваете 4 миллиона строк, вы должны поместить результат где-то. Это таблица только для чтения? Вы единственный пользователь? Или у вас тоже есть (одновременный) доступ на запись? Рассмотрите инструкции для вопросов [postgresql-performance]: stackoverflow.com/tags/postgresql-performance/info   -  person Erwin Brandstetter    schedule 13.09.2015


Ответы (1)


Индекс покрытия

Раздел по customerid, например @Daniel прокомментировал . integer меньше и дешевле в сортировке. Если вам не нужен customername в результате, полностью замените его на customerid.

Может помочь индекс с несколькими столбцами (например, @ wildplasser прокомментировал). Если это (в основном) таблица только для чтения, «покрывающий» индекс, который позволяет сканирование только для индекса, будет еще быстрее, особенно если включенные столбцы малы:

CREATE INDEX orders_nbr_idx ON orders (customerid, orderdate, orderid);

Добавление orderid к индексу имеет смысл только в том случае, если вы получаете из него сканирование только для индекса. Если вам нужен customername, добавьте и его. Более:

Если это (в основном) таблица только для чтения, выполните дорогостоящий запрос один раз и сохраните снимок как MATERIALIZED VIEW для повторного использования...

Арахис

Вы можете сделать несколько небольших вещей, чтобы уменьшить объем памяти. После воспроизведения тетрис столбца это сэкономит 0-7 байтов на строку, в настоящее время потерянную для заполнения:

CREATE TABLE orders (
  orderid integer,
  customerid integer,
  amount money,
  tax money,
  orderdate date,
  status text,
  customername text,
  customerstate text
  );

Если вы запишете результат в другую таблицу (или MATERIALIZED VIEW), это позволит немного сэкономить на оптимизации запроса аналогичным образом. rank() производит bigint, приведя к int, вы сохраните 8 байтов на строку (4 + 4 заполнения):

SELECT orderid, customername, orderdate
    -- orderid, customerid, orderdate  -- good enough?
     , rank() OVER (PARTITION BY customerid
                    ORDER BY orderdate)::int AS cust_ord_nbr
FROM   orders;
person Erwin Brandstetter    schedule 13.09.2015
comment
Спасибо за совет по материализованному представлению! Собираюсь попробовать и отчитаться. - person Jeffrey James; 15.09.2015