Очень медленное сканирование кучи растровых изображений в Postgres - PullRequest
6 голосов
/ 24 октября 2010

У меня есть следующая простая таблица, которая содержит данные измерения трафика:

CREATE TABLE "TrafficData"
(
  "RoadID" character varying NOT NULL,
  "DateID" numeric NOT NULL,
  "ExactDateTime" timestamp NOT NULL,
  "CarsSpeed" numeric NOT NULL,
  "CarsCount" numeric NOT NULL
)
CREATE INDEX "RoadDate_Idx" ON "TrafficData" USING btree ("RoadID", "DateID");

Столбец RoadID однозначно идентифицирует дорогу, данные которой записываются, а DateID определяет день года (1..365) данных - в основном округленное представление ExactDateTime.

У меня около 100.000.000 строк; в столбце «RoadID» имеется 1000 различных значений, а в столбце «DateID» - 365 различных значений.

Затем я запускаю следующий запрос:

SELECT * FROM "TrafficData"
WHERE "RoadID"='Station_1'
AND "DateID">20100610 AND "DateID"<20100618;

Это занимает до трех ошеломляющих секунд, чтобы закончить, и я не могу на всю жизнь понять, ПОЧЕМУ.

EXPLAIN ANALYZE дает мне следующий вывод:

Bitmap Heap Scan on "TrafficData"  (cost=104.84..9743.06 rows=2496 width=47) (actual time=35.112..2162.404 rows=2016 loops=1)
  Recheck Cond: ((("RoadID")::text = 'Station_1'::text) AND ("DateID" > 20100610::numeric) AND ("DateID" < 20100618::numeric))
  ->  Bitmap Index Scan on "RoadDate_Idx"  (cost=0.00..104.22 rows=2496 width=0) (actual time=1.637..1.637 rows=2016 loops=1)
        Index Cond: ((("RoadID")::text = 'Station_1'::text) AND ("DateID" > 20100610::numeric) AND ("DateID" < 20100618::numeric))
Total runtime: 2163.985 ms

Мои характеристики:

  • Windows 7
  • Postgres 9,0
  • 4 ГБ ОЗУ

Буду очень признателен за полезные советы!

Ответы [ 3 ]

4 голосов
/ 24 октября 2010

Медленная часть явно извлекает данные из таблиц, поскольку доступ к индексу кажется очень быстрым.Вы можете либо оптимизировать параметры использования ОЗУ (см. http://wiki.postgresql.org/wiki/Performance_Optimization и http://www.varlena.com/GeneralBits/Tidbits/perf.html),, либо оптимизировать расположение данных в таблице, введя команду CLUSTER (см. http://www.postgresql.org/docs/8.3/static/sql-cluster.html).

CLUSTER "TrafficData" USING "RoadDate_Idx";

должен это сделать.

2 голосов
/ 27 октября 2010

В дополнение к ответу Даниэля, кластерная операция - это однократный процесс, который перестраивает данные на диске. Цель состоит в том, чтобы получить 2000 строк результатов из меньшего количества дисковых блоков.

Поскольку это фиктивные данные, которые используются для того, чтобы выяснить, как вы можете быстро запросить их, я бы порекомендовал перезагрузить их в шаблоне, более близком к тому, как они будут загружаться при его создании. Я предполагаю, что данные генерируются один день за раз, что эффективно приведет к сильной корреляции между DateID и местоположением на диске. Если это так, то я либо сгруппировал бы по DateID, либо разделил бы ваши тестовые данные на 365 отдельных загрузок и перезагрузил бы их.

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

Я бы также проверил, что все, что у вас работает в Windows 7, не добавляет времени к тем чтениям, которые вам не нужны, например, гарантирует, что прочитанные блоки не содержат сигнатур вирусов, или одновременно выполняет автоматически запланированная дефрагментация диска (в результате чего головка диска почти никогда не приближается к тому месту, где она была в последний раз при чтении блока базы данных).

0 голосов
/ 24 октября 2010
  • 4 ГБ ОЗУ -> 6+ у вас есть 100M записей, что невелико, но для настольного компьютера память может иметь значение. Если это не рабочий стол, я не уверен, почему у вас такой маленький объем памяти
  • AND "DateID">20100610 AND "DateID"<20100618; -> DateID BETWEEN 20100611 AND 20100617;
  • Создать индекс по DateID
  • Избавьтесь от всех двойных кавычек вокруг имен полей
  • Вместо VarChar, сделайте RoadID текстовое поле
...