2013-12-17 3 views
1

Я пытаюсь подсчитать количество записей в таблице. Таблица называется принадлежностью и имеет только 4 столбца (2 из которых являются внешними ключами)Лучше/более эффективный способ написать этот запрос

Я хочу подсчитать количество записей, в которых аффилированный столбец равен 0, а business_id связан с определенной учетной записью.

Я знаю, как сделать этот запрос, используя ключевое слово IN, но мне было интересно, есть ли лучший или более эффективный способ сделать это.

Это версия IN запроса:

SELECT COUNT(1) FROM affiliations 
WHERE business_id IN (
    SELECT business_id 
    FROM affiliations 
    WHERE account_email = '[email protected]' 
) AND affiliated = 0 

Я понимаю, я мог бы заменить это с EXISTS:

SELECT COUNT(1) FROM affiliations 
WHERE EXISTS (
    SELECT 1 FROM affiliations 
    WHERE account_email = '[email protected]' 
) AND affiliated = 0 

Будет ли заявление с EXISTS работу? И как уже было сказано, есть ли лучший способ сделать это?

Заранее благодарен!

+0

Некоторая дополнительная информация: business_id не является уникальным в этой таблице. В базе данных есть много разных взаимоотношений между учетными записями и предприятиями, и эта таблица содержит связанные с учетной записью и business_ids. Я выбираю account_email и хочу, чтобы все бизнес-объекты, с которыми связана эта учетная запись, а затем подсчитали количество учетных записей, которые также связаны с каждым из этих предприятий. –

+0

Пожалуйста, опубликуйте вывод EXPLAIN ANALYZE этого запроса – hd1

+0

как насчет подсчета business_id для account_email = '[email protected]' и affiliated = 0 – faisal

ответ

0

Первый запрос от вопроса с IN п не эквивалентна второй с EXIST.

Чтобы преобразовать первый запрос с IN, вы должны использовать зависимую подзапрос:

SELECT COUNT(1) FROM affiliations a1 
WHERE EXISTS (
    SELECT 1 FROM affiliations a2 
    WHERE account_email = '[email protected]' 
     AND a1.business_id = a2.business_id 
) AND affiliated = 0 

Обратите внимание на это условие: AND a1.business_id = a2.business_id

выше запрос семантически eqivalent к вашему первому запросу с IN.
Их показатели являются такими же, как хорошо, потому MySql, во время фазы оптимализация, преобразует intenrally состояние этой формы:

outer_expr IN (SELECT inner_expr FROM ... WHERE subquery_where)

в этом:

EXISTS (SELECT 1 FROM ... WHERE subquery_where AND outer_expr=inner_expr)

Смотрите эту ссылку detalis: http://dev.mysql.com/doc/refman/5.0/en/subquery-optimization-with-exists.html
Обратите особое внимание на обсуждение значений NULL и как NULL влияет на оптимизатор.

Вкратце - если business_id столбец объявлен как NOT NULL, то MySql может оптимизировать эти два запроса.
См окончательный вывод (в нижней части страницы в этой ссылке):

Чтобы оптимизатор запросов лучше выполнять запросы использовать эти советы:

  • Столбец должен быть объявлен как NOT NULL, если это действительно так. (Это также помогает другим аспектам оптимизатора.)

  • Если вам не нужно отличать результат NULL от FALSE в подзапросе, вы можете легко избежать медленного пути выполнения. Заменить сравнение, которое выглядит следующим образом:

    outer_expr IN (SELECT inner_expr FROM ...)

    с этим выражением:

    (outer_expr IS NOT NULL) И (outer_expr IN (SELECT inner_expr FROM ...))

    Тогда NULL IN (SELECT ...) никогда не будет оценен, потому что MySQL перестает оценивать И-части, как только результат выражения становится ясным.

+0

Спасибо за информацию, это полезно и интересно. –

-1

Используйте JOIN вместо IN. В страшно для исполнения, если вы пытаетесь соответствовать много значений

SELECT COUNT(1) 
FROM affiliations AS ABB2 
    JOIN (SELECT business_id 
      FROM affiliations 
      WHERE account_email = '[email protected]') AS ABB1 
     ON ABB1.business_id = ABB2.business_id 
WHERE affiliated = 0 
+0

@Lloyd, JOIN в семантически эквивалентном SEMI JON (существует/в), см. Эту демонстрацию: http://www.sqlfiddle.com/#!2/b228c/1 обратите внимание на результаты вашего запроса и запрос от ответ. Кроме того, производительность IN может быть плохим, если IN содержит огромный список значений (констант), но это не относится к запросу с 'IN (subquery)', MySql может оптимизировать такой запрос, и он может быть еще быстрее, чем stringht jonin. – krokodilko

+0

Хорошо, спасибо за информацию. Я, вероятно, просто придерживаюсь инструкции IN. Я думаю, что ключевое слово IN существует по какой-то причине, и это похоже на хороший случай, чтобы использовать его. –

+0

@kordirko Я был в предположении, что business_id был уникальным. Если нет, вы можете добавить GROUP BY в подзапрос, и вы получите те же результаты. Я знаю несколько краевых случаев, где IN может быть немного быстрее, чем прямой JOIN, но в подавляющем большинстве сценариев JOIN - это то же самое, если не быстрее IN. Это особенно верно в старой версии MySQL или тех, которые не запускают InnoDB. –

1

Я хотел бы использовать существует, но и не забывайте соотносить подзапрос к первичной таблице ниже.

SELECT COUNT(1) FROM affiliations a 
WHERE exists (
    SELECT 1 
    FROM affiliations a1 
    WHERE account_email = '[email protected]' 
    and a1.business_id=a.business_id 
) AND affiliated = 0 
Смежные вопросы