SQL: помогите мне оптимизировать мой SQL - PullRequest
1 голос
/ 24 июня 2009

Я хочу оптимизировать свой SQL.

Моя схема базы данных:

ДОМА

  • home_id
  • адрес
  • город
  • состояние
  • молния
  • primary_photo_group_id

HOME_PHOTOS

  • photo_id (первичный ключ)
  • home_id (домашний первичный ключ)
  • photo_group_id (группа фотографий - это одно и то же изображение, изменение размера от миниатюры до большого размера)
  • home_photo_type_id (размер изображения, будь то миниатюра или большой размер)
  • photo_url_dir (расположение файловой системы, в которой хранится фотография)

Проблема

Вполне возможно, что у "дома" нет фотографии, связанной с домом. В этом случае primary_photo_group_id = 0 . Otherwise, primary_photo_group_id` равно group_id фотографии для использования в качестве основной фотографии.

Медленный SQL (b / c из UNION)

SELECT  homes.home_id,
    address,
    city,
    state,
    zip,
    photo_id,
    photo_url_dir
FROM homes, home_photos
WHERE homes.home_id = home_photos.home_id
AND primary_photo_group_id = home_photo_group_id
AND home_photo_type_id = 2

UNION

SELECT  homes.home_id,
    address,
    city,
    state,
    zip,
    null,
    null
FROM homes
WHERE primary_photo_group_id = 0

Что бы я хотел сделать

Я бы хотел избавиться от UNION, так как мне пришлось искать по всей таблице 2 раза. Как я могу избавиться от UNION, так как мне нужно проверить случай, когда primary_photo_group_id = 0 и если он не равен 0, то запросить home_photos таблицу

Вот псевдокод, который должен произойти

SELECT  homes.home_id,
    address,
    city,
    state,
    zip,
    photo_id,  (include only if primary_photo_group_id != 0)
    photo_url_dir  (include only if primary_photo_group_id != 0)
FROM homes,
    home_photos (include only if primary_photo_group_id != 0)
WHERE 
    primary_photo_group_id = 0
ELSE
    homes.home_id = home_photos.home_id
        AND primary_photo_group_id = home_photo_group_id
        AND home_photo_type_id = 2

Ответы [ 4 ]

1 голос
/ 24 июня 2009
SELECT  homes.home_id,
        address,
        city,
        state,
        zip,
        photo_id,
        photo_url_dir
FROM    homes
LEFT JOIN
        home_photos
ON      home_photos.home_id = homes.home_id
        AND home_photo_group_id = CASE WHEN primary_photo_group_id = 0 THEN NULL ELSE primary_photo_group_id END
        AND home_photo_type_id = 2

Наличие составного индекса на home_photos (home_id, home_photo_group_id, home_photo_type_id) значительно улучшит этот запрос.

Обратите внимание, что использование CASE несколько более эффективно, чем присоединение слева на 0, даже если в home_photos.

нет записей с home_photo_group_id = 0

Когда MySQL видит JOIN на NULL (который по определению ничего не может дать), он даже не заглядывает в объединенную таблицу. Когда он присоединяется к 0, он все равно должен проверить индекс и убедиться, что никакого значения не существует.

Это не очень сильно влияет на производительность, но все же может улучшить время вашего запроса на несколько процентов, особенно если у вас много 0 в homes.

Смотрите эту запись в моем блоге для подробностей производительности:

Также обратите внимание, что ваши таблицы не в 2NF.

Ваш group_id зависит от home_id, и включение его в home_photos является нарушением 2NF.

Это не всегда плохо, но управлять им может быть сложнее.

1 голос
/ 24 июня 2009

Если второй запрос медленнее, чем первый, это потому, что у вас есть индекс на {home_id, primary_photo_group_id} (или, возможно, просто {home_id}), но не только на {primary_photo_group_id}. Вам нужен индекс для этого столбца, если вы хотите повысить производительность поиска в этом столбце.

0 голосов
/ 24 июня 2009

Может быть, вы не знаете о левом внешнем соединении? Попробуйте:

SELECT  homes.home_id,
    address,
    city,
    state,
    zip,
    photo_id
    photo_url_dir 
FROM homes h
left outer join home_photos hp on h.home_id = hp.home_id
    AND primary_photo_group_id = home_photo_group_id
    AND home_photo_type_id = 2
0 голосов
/ 24 июня 2009

Читать о [Joins] (http://en.wikipedia.org/wiki/Join_(SQL)

 Select * from table_a, table_b

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

Редактировать : Я не просто дал вам ответ, потому что я думал, что это домашнее задание, но я все равно не просто дам вам ответ, потому что внешние объединения достаточно важны, чтобы знать о них, даже если вы просто пишете SQL для веб-сайта. вы будете лучше учиться этому и использовать это в качестве примера.

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