Индексы, которые могут быть полезны и должны рассматриваться как имеющие отношение к
WHERE c.root = 100
AND cs.catalog = c.id
AND cs.securitygroup = 200
AND cu.catalog = c.id
AND cu.university = 300
Таким образом, следующие поля могут быть интересны для индексов
c: id, root
cs: catalog, securitygroup
cu: catalog, university
Итак, попробуйте создать
(catalog_securitygroup.catalog, catalog_securitygroup.securitygroup)
и
(catalog_university.catalog, catalog_university.university)
РЕДАКТИРОВАТЬ: Я пропустил ORDER BY - эти поля также следует учитывать, поэтому
(catalog.name, catalog.id)
может быть полезным (или некоторый другой составной индекс, который можно использовать для сортировки и условий - возможно (catalog.root, catalog.name, catalog.id))
EDIT2 Хотядругой вопрос принят, я дам еще немного пищи для размышлений.Я создал несколько тестовых данных и провел несколько тестов.
Тестовые случаи минимальны с точки зрения ширины записи (в catalog_securitygroup и catalog_university первичными ключами являются (каталог, группа безопасности) и (каталог, университет)).Вот количество записей в таблице:
test=# SELECT (SELECT COUNT(*) FROM catalog), (SELECT COUNT(*) FROM catalog_securitygroup), (SELECT COUNT(*) FROM catalog_university);
?column? | ?column? | ?column?
----------+----------+----------
500000 | 1497501 | 500000
(1 row)
База данных postgres 8.4, установка Ubuntu по умолчанию, аппаратное обеспечение i5, 4GRAM
Сначала я переписал запрос на
SELECT c.id, c.name, c.owner
FROM catalog c, catalog_securitygroup cs, catalog_university cu
WHERE c.root < 50
AND cs.catalog = c.id
AND cu.catalog = c.id
AND cs.securitygroup < 200
AND cu.university < 200
ORDER BY c.name
LIMIT 50 OFFSET 100
примечание: условия преобразуются в меньшее, чем для поддержания сопоставимого количества промежуточных строк (приведенный выше запрос вернул бы 198 801 строк без предложения LIMIT)
При выполнении, как указано выше, без каких-либо дополнительных индексов (за исключением PKи внешние ключи) он запускается в 556 мс в холодной базе данных (это фактически указывает на то, что я как-то упростил выборочные данные - я был бы счастлив, если бы у меня здесь было 2-4 с, не прибегая к меньшему количеству операторов)
Это подводит меня к моей точке зрения - любой прямой запрос, который только объединяет и фильтрует (определенное количество таблиц) и возвращает только определенное количество записей, должен выполняться под единицей в любой приличной базе данных без необходимости использовать курсоры илиденормализовать данные (на днях мне придется написать сообщение об этом).
Кроме того, если запросвозвращает только 50 строк и выполняет простые объединения на равные и ограничительные условия равенства, он должен работать даже намного быстрее.
Теперь давайте посмотрим, добавлю ли я некоторые индексы, наибольший потенциал в таких запросах, как правило, это порядок сортировки, поэтомуя попробую это:
CREATE INDEX test1 ON catalog (name, id);
Это делает время выполнения запроса - 22 мс в холодной базе данных.
И это точка -если вы пытаетесь получить только страницу данных, вы должны получить только страницу данных и время выполнения запросов, например, для нормализованных данных с правильными индексами должно занять меньше100 мс на приличном оборудовании.
Надеюсь, я не упростил дело до такой степени, чтобы не сравнивать его (как я уже говорил ранее, присутствует некоторое упрощение, поскольку я не знаю кардинальности отношений между каталогом и многими другими).для многих таблиц).
Итак, вывод
- на вашем месте я бы не прекратил подстройку индексов (и SQL), пока не получуВыполнение запроса должно быть меньше 200 мс, как правило.
- , только если я найду объективное объяснение, почему он не может опуститься ниже такого значения, я прибегну к денормализации и / или курсорам и т. д..