Как оптимизировать select из нескольких таблиц с миллионами строк

Имеются следующие таблицы (Oracle 10g):

catalog (
  id NUMBER PRIMARY KEY,
  name VARCHAR2(255),
  owner NUMBER,
  root NUMBER REFERENCES catalog(id)
  ...
)
university (
  id NUMBER PRIMARY KEY,
  ...
)
securitygroup (
  id NUMBER PRIMARY KEY
  ...
)
catalog_securitygroup (
  catalog REFERENCES catalog(id),
  securitygroup REFERENCES securitygroup(id)
)
catalog_university (
  catalog REFERENCES catalog(id),
  university REFERENCES university(id)
)

Каталог: 500 000 строк, catalog_university: 500 000, catalog_securitygroup: 1 500 000.

Мне нужно выбрать любые 50 строк из каталога с указанным корнем, упорядоченные по имени для текущего университета и текущей группы безопасности. Есть запрос:

SELECT ccc.* FROM (
  SELECT cc.*, ROWNUM AS n FROM (
      SELECT c.id, c.name, c.owner
        FROM catalog c, catalog_securitygroup cs, catalog_university cu
        WHERE c.root = 100
          AND cs.catalog = c.id
          AND cs.securitygroup = 200
          AND cu.catalog = c.id
          AND cu.university = 300
        ORDER BY name
    ) cc 
) ccc WHERE ccc.n > 0 AND ccc.n <= 50;

Где 100 - некоторый каталог, 200 - некоторая securitygroup, 300 - некоторый университет. Этот запрос возвращает 50 строк из ~ 170 000 за 3 минуты.

Но следующий запрос возвращает эти строки за 2 сек:

SELECT ccc.* FROM (
  SELECT cc.*, ROWNUM AS n FROM (
      SELECT c.id, c.name, c.owner
        FROM catalog c
        WHERE c.root = 100
        ORDER BY name
    ) cc 
) ccc WHERE ccc.n > 0 AND ccc.n <= 50;

Я строю следующие индексы: (catalog.id, catalog.name, catalog.owner), (catalog_securitygroup.catalog, catalog_securitygroup.index), (catalog_university.catalog, catalog_university.university).

План первого запроса (с использованием PLSQL Developer):

http://habreffect.ru/66c/f25faa5f8/plan2.jpg

План второго запроса:

http://habreffect.ru/f91/86e780cc7/plan1.jpg

Какие есть способы оптимизации имеющегося у меня запроса?

7
задан Anton Schukin 17 November 2010 в 16:30
поделиться