Как избежать вложенного SQL-запроса в этом случае? - PullRequest
1 голос
/ 25 января 2010

У меня есть вопрос SQL, связанный с этим и этим вопросом (но другим). В основном я хочу знать, как я могу избежать вложенного запроса.

Допустим, у меня есть огромная таблица заданий (jobs), выполненных компанией в их истории. Эти работы характеризуются годом, месяцем, местоположением и кодом, принадлежащим инструменту, используемому для работы. Кроме того, у меня есть таблица инструментов (tools), перевод кодов инструментов в описания инструментов и дополнительные данные об инструменте. Теперь им нужен веб-сайт, на котором они могут выбрать год, месяц, местоположение и инструмент с помощью раскрывающегося списка, после чего будут отображаться соответствующие задания. Я хочу заполнить последний выпадающий список только соответствующими инструментами, соответствующими выбранному перед годом, месяцу и местоположению, поэтому я пишу следующий вложенный запрос:

SELECT c.tool_code, t.tool_description
FROM (
 SELECT DISTINCT j.tool_code
 FROM jobs AS j
 WHERE j.year = ....
        AND j.month = ....
 AND j.location = ....
) AS c
LEFT JOIN tools as t
ON c.tool_code = t.tool_code
ORDER BY c.tool_code ASC

Я прибег к этому вложенному запросу, потому что это было намного быстрее, чем выполнить JOIN для всей базы данных и выбрать из этого. Время моего запроса сильно сократилось. Но поскольку я недавно прочитал, что вложенных запросов MySQL следует избегать любой ценой , мне интересно, ошибаюсь ли я в этом подходе. Должен ли я переписать свой запрос по-другому? И как?

Ответы [ 2 ]

2 голосов
/ 25 января 2010

Вы можете избежать подзапроса, используя GROUP BY, но если подзапрос работает лучше, оставьте его.

Почему вы используете LEFT JOIN вместо JOIN для присоединения tools?

2 голосов
/ 25 января 2010

Нет, вы не должны, ваш запрос в порядке.

Просто создайте индекс для jobs (year, month, location, tool_code) и tools (tool_code), чтобы можно было использовать INDEX FOR GROUP-BY.

В статье, которую вы предоставили, описаны предикаты подзапроса (IN (SELECT ...)), а не вложенные запросы (SELECT FROM (SELECT ...)).

Даже с подзапросами статья ошибочна: хотя MySQL не может оптимизировать все подзапросы, он отлично справляется с IN (SELECT …) предикатами.

Я не знаю, почему автор решил поставить DISTINCT здесь:

SELECT  id, name, price
FROM    widgets
WHERE   id IN
        (
        SELECT  DISTINCT widgetId
        FROM    widgetOrders
        )

и почему они думают, что это поможет повысить производительность, но, учитывая, что widgetID проиндексирован, MySQL просто преобразует этот запрос:

SELECT  id, name, price
FROM    widgets
WHERE   id IN
        (
        SELECT  widgetId
        FROM    widgetOrders
        )

в index_subquery

По сути, это похоже на предложение EXISTS: внутренний подзапрос будет выполняться один раз для строки widgets с добавленным дополнительным предикатом:

SELECT  NULL
FROM    widgetOrders
WHERE   widgetId = widgets.id

и остановка на первом матче в widgetOrders.

Этот запрос:

SELECT  DISTINCT w.id,w.name,w.price
FROM    widgets w
INNER JOIN
        widgetOrders o
ON      w.id = o.widgetId

придется использовать temporary, чтобы избавиться от дубликатов, и будет намного медленнее.

...