Замена серии LEFT JOIN чем-то другим? - PullRequest
0 голосов
/ 16 июля 2011

У меня есть люди, компании и сотрудники. Каждая из этих таблиц имеет внешний ключ обратно к таблице, которую я называю сторонами, которая поддерживает одноуровневую запись через триггеры. Стороны имеют от 0 до N site_locators, которые сами ссылаются на сайты, которые ссылаются на города.

Я создаю представление, которое возвращает полное имя адресата и его город. Код в таком виде:

  SELECT
      surname
    , rest_of_name
    , 'Employee'  AS party_type_code
    , party_id
    , cities.name AS city_name
  FROM
              employees
    LEFT JOIN site_locators USING (party_id)
    LEFT JOIN sites         USING (site_id)
    LEFT JOIN cities        USING (city_id)
UNION ALL
  SELECT
      surname
    , NULL::text
    , 'Company'  AS party_type_code
    , party_id
    , cities.name AS city_name
  FROM
              companies
    LEFT JOIN site_locators USING (party_id)
    LEFT JOIN sites         USING (site_id)
    LEFT JOIN cities        USING (city_id)
UNION ALL
  SELECT
      surname
    , rest_of_name
    , 'Person'  AS party_type_code
    , party_id
    , cities.name AS city_name
  FROM
              people
    LEFT JOIN site_locators USING (party_id)
    LEFT JOIN sites         USING (site_id)
    LEFT JOIN cities        USING (city_id)

Мне не очень нравятся множественные ЛЕВЫЕ СОЕДИНЕНИЯ в каждом СОЮЗЕ. Я реорганизовал код, чтобы выполнить СОЕДИНЕНИЕ только один раз как отдельный шаг:

SELECT
    parties.*
  , cities.name AS city_name
FROM (
    SELECT /* As above, minus city_name */
    FROM employees
  UNION ALL
    SELECT /* As above, minus city_name */
    FROM companies
  UNION ALL
    SELECT /* As above, minus city_name */
    FROM people
  ) AS parties
  LEFT JOIN site_locators USING (party_id)
  LEFT JOIN sites         USING (site_id)
  LEFT JOIN cities        USING (city_id)

Этот второй запрос выполняется быстрее, потому что СОЕДИНЕНИЯ происходят только один раз после фильтрации всех таблиц. Что мне интересно, так это то, что если я смогу провести дальнейший рефакторинг, чтобы, если site_locators не возвращал строки для вечеринки, мне даже не нужно было искать сайты или города? Мне интересно, если это можно переписать с некоторыми внутренними соединениями, а не со всеми левыми соединениями. У меня был неудачный опыт работы с левыми соединениями, и я хочу сократить их количество.

ПРИМЕЧАНИЕ. Таблица сторон существует для уменьшения количества таблиц. Если бы его не было, мне бы понадобились таблицы для каждого типа группы и типа локатора: employee_site_locators, people_site_locators, company_site_locators, employee_email_locators, people_email_locators и так далее. С таблицей сторон у меня может быть одна таблица * _locator для каждого типа локатора.

1 Ответ

0 голосов
/ 21 марта 2013

Во-первых, этот первый рефакторинг очень хорош.

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

В общем, лучше сначала сосредоточиться на ясности, а затем смотреть на настройку, чтобы работать лучше, чемсначала заботьтесь о производительности, а потом работайте над ясностью.Однако одна вещь, которая поможет, - это заменить USING на ON.. Наконец, посмотрите на вашу модель и посмотрите, что на самом деле является левым соединением, а что внутренним.Обратите внимание, что они очень разные, поэтому их нельзя заменить напрямую.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...