Я использую PostgreSQL 8.3 на 1,83 ГГц Intel Core Duo Mac Mini с 1 ГБ оперативной памяти и Mac OS X 10.5.8. Я храню огромный граф в моей базе данных PostgreSQL. Он состоит из 1,6 миллиона узлов и 30 миллионов ребер. Моя схема базы данных выглядит так:
CREATE TABLE nodes (id INTEGER PRIMARY KEY,title VARCHAR(256));
CREATE TABLE edges (id INTEGER,link INTEGER,PRIMARY KEY (id,link));
CREATE INDEX id_idx ON edges (id);
CREATE INDEX link_idx ON edges (link);
Данные в краях таблицы выглядят как
id link
1 234
1 88865
1 6
2 365
2 12
...
Таким образом, он сохраняет для каждого узла с идентификатором x исходящую ссылку на идентификатор y.
Время поиска всех исходящих ссылок в порядке:
=# explain analyze select link from edges where id=4620;
QUERY PLAN
---------------------------------------------------------------------------------
Index Scan using id_idx on edges (cost=0.00..101.61 rows=3067 width=4) (actual time=135.507..157.982 rows=1052 loops=1)
Index Cond: (id = 4620)
Total runtime: 158.348 ms
(3 rows)
Однако, если я ищу входящие ссылки на узел, база данных будет более чем в 100 раз медленнее (хотя итоговое количество входящих ссылок только в 5-10 раз превышает количество исходящих ссылок):
=# explain analyze select id from edges where link=4620;
QUERY PLAN
----------------------------------------------------------------------------------
Bitmap Heap Scan on edges (cost=846.31..100697.48 rows=51016 width=4) (actual time=322.584..48983.478 rows=26887 loops=1)
Recheck Cond: (link = 4620)
-> Bitmap Index Scan on link_idx (cost=0.00..833.56 rows=51016 width=0) (actual time=298.132..298.132 rows=26887 loops=1)
Index Cond: (link = 4620)
Total runtime: 49001.936 ms
(5 rows)
Я пытался заставить Postgres не использовать растровое сканирование через
=# set enable_bitmapscan = false;
но скорость запроса входящих ссылок не улучшилась:
=# explain analyze select id from edges where link=1588;
QUERY PLAN
-------------------------------------------------------------------------------------------
Index Scan using link_idx on edges (cost=0.00..4467.63 rows=1143 width=4) (actual time=110.302..51275.822 rows=43629 loops=1)
Index Cond: (link = 1588)
Total runtime: 51300.041 ms
(3 rows)
Я также увеличил свои общие буферы с 24 МБ до 512 МБ, но это не помогло. Поэтому мне интересно, почему мои запросы на исходящие и входящие ссылки демонстрируют такое асимметричное поведение? Что-то не так с моим выбором индексов? Или мне лучше создать третью таблицу, содержащую все входящие ссылки для узла с идентификатором x? Но это было бы довольно пустой тратой дискового пространства. Но так как я новичок в базах данных SQL, может быть, мне здесь чего-то не хватает?