Выполнение JOIN vs SELECT ... WHERE с примером - PullRequest
1 голос
/ 20 ноября 2010

Я нашел этот пример в MySQL Tutorial:

SELECT article, dealer, price
FROM   shop
WHERE  price=(SELECT MAX(price) FROM shop);

Мой вопрос: выполняется ли подзапрос (SELECT MAX (цена) ОТ магазина) один раз или выполняется несколько раз, пока не будет найдена максимальная цена для запроса?

С точки зрения производительности это другое решение лучше?

SELECT s1.article, s1.dealer, s1.price
FROM shop s1
LEFT JOIN shop s2 ON s1.price < s2.price
WHERE s2.article IS NULL;

Спасибо.

Ответы [ 7 ]

2 голосов
/ 20 ноября 2010

Подзапрос не коррелирован, поэтому любая разумная реализация оценит его только один раз. Обратите внимание, что MySQL имеет проблему с IN, хотя семантически эквивалентный

SELECT article, dealer, price
FROM   shop
WHERE  price IN (SELECT MAX(price) FROM shop);

Приводит к тому, что подзапрос оценивается несколько раз.

Что касается оценки производительности, вам нужно взглянуть на explain plan для обоих в вашей конкретной СУБД.

Наиболее эффективным решением может быть использование SELECT TOP .. WITH TIES или эквивалентного, если у вас есть индекс покрытия в столбце price, а ваша СУБД имеет такую ​​конструкцию.

1 голос
/ 20 ноября 2010

чтобы ответить на ваш вопрос, скалярный подзапрос (SELECT MAX (цена) из магазина) запускается один раз, а затем передается в основной запрос в качестве значения в MySQL.

Так что этот запрос так же быстр, как и все остальное, что вы можете придумать.

1 голос
/ 20 ноября 2010

У вас есть теги для MySql, T-Sql и PL / Sql, я подозреваю, что ответ для каждого разный.

Ответ также может зависеть от того, какие у вас индексы и насколько уникальныполе [цена]:

Запустите анализатор запросов, чтобы увидеть, каков фактический план запроса.

0 голосов
/ 20 ноября 2010

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

0 голосов
/ 20 ноября 2010

Я использовал SQL Server 2008 для этих трех вариантов Aquery. В моем тестировании я запрашиваю базу данных AdventureWorks, используя ProductInventory в схеме Production. Три запроса:

declare @max int
Select @max =  MAX(Quantity) FROM [AdventureWorks].[Production].[ProductInventory]
SELECT TOP 1000 [ProductID]
      ,[LocationID]
      ,[Shelf]
      ,[Bin]
      ,[Quantity]
      ,[rowguid]
      ,[ModifiedDate]
  FROM [AdventureWorks].[Production].[ProductInventory]
  WHERE Quantity = @max

SELECT TOP 1000 [ProductID]
      ,[LocationID]
      ,[Shelf]
      ,[Bin]
      ,[Quantity]
      ,[rowguid]
      ,[ModifiedDate]
  FROM [AdventureWorks].[Production].[ProductInventory]
  WHERE Quantity = (Select MAX(Quantity) FROM [AdventureWorks].[Production].[ProductInventory])


SELECT TOP 1000 AW1.[ProductID]
      ,AW1.[LocationID]
      ,AW1.[Shelf]
      ,AW1.[Bin]
      ,AW1.[Quantity]
      ,AW1.[rowguid]
      ,AW1.[ModifiedDate]
  FROM [AdventureWorks].[Production].[ProductInventory] AW1
LEFT JOIN [AdventureWorks].[Production].[ProductInventory] AW2 ON AW1.Quantity < AW2.Quantity
WHERE AW2.ProductID IS NULL; 

Используя значок «Показать примерный план запроса», я могу сравнить события исключения для трех случаев. Результаты:

  1. Объявление переменной и ее заполнение выполняется на 5% быстрее, чем выбор в предложении where.
  2. Объединение на 98% медленнее, чем подвыбор
  3. Объединение на 99% медленнее, чем переменная

Я предлагаю объявить переменную и заполнить ее. Используйте переменную в предложении WHERE

0 голосов
/ 20 ноября 2010

Использование объединения должно быть лучше, чем вложенный подзапрос.

0 голосов
/ 20 ноября 2010

Я могу побить оба:

SELECT article, dealer, price
FROM   shop
WHERE  price=MAX(price)

Редактировать: Упс, не работает на моем тестовом сервере: /

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