Лучший способ проверить, существует ли строка в таблице MySQL

Я пытаюсь выяснить, существует ли строка в таблице. Используя MySQL, лучше сделать такой запрос:

SELECT COUNT(*) AS total FROM table1 WHERE ...

и проверьте, не равна ли сумма нулю или лучше выполнить такой запрос:

SELECT * FROM table1 WHERE ... LIMIT 1

и проверьте, были ли возвращены какие-либо строки?

В обоих запросах предложение WHERE использует индекс.


person Bernard Chen    schedule 04.11.2009    source источник


Ответы (12)


Вы также можете попробовать EXISTS:

SELECT EXISTS(SELECT * FROM table1 WHERE ...)

и согласно документации, вы можете SELECT что угодно.

Традиционно подзапрос EXISTS начинается с SELECT *, но он может начинаться с SELECT 5 или SELECT column1 или с чего угодно. MySQL игнорирует список SELECT в таком подзапросе, поэтому это не имеет значения.

person Chris Thompson    schedule 04.11.2009
comment
Протестируйте с ...EXISTS( SELECT 1/0 FROM someothertable). Для SQL Server и Oracle - нет никакой разницы в использовании *, 1 или NULL, потому что EXISTS проверяет только логическое значение на основе 1+ соответствия критериев WHERE. - person OMG Ponies; 05.11.2009
comment
Ребята, прямо в документации, связанной с этим ответом, во втором абзаце сказано: Традиционно подзапрос EXISTS начинается с SELECT *, но он может начинаться с SELECT 5 или SELECT column1 или чего угодно вообще. MySQL игнорирует список SELECT в таком подзапросе, поэтому это не имеет значения. - person mpen; 11.02.2012
comment
@ChrisThompson: что происходит при выполнении оператора? Я имею в виду, что содержится в результирующем наборе? - person Ashwin; 04.11.2012
comment
@Ashwin, он содержит значение 0 (не существует) или 1 (существует). - person fedorqui 'SO stop harming'; 07.02.2013
comment
Возвращает ли оператор тип bool или тип беззнакового символа? Я разрабатываю с использованием C API, и мне нужно это знать. Спасибо. - person Luka; 25.02.2014
comment
Я считаю, что ваш запрос лишний, я тестировал, и этот запрос SELECT 1 FROM table1 WHERE col = $var LIMIT 1 быстрее вашего запроса. Так в чем же преимущество вашего запроса? - person Shafizadeh; 28.09.2015
comment
@Shafizadeh делает отличную мысль, которую легко упустить из виду. Как вариант выше отсутствует SELECT 1 FROM test WHERE ... LIMIT 1, без SELECT EXISTS вокруг него. Так может быть на волосок быстрее. - person ToolmakerSteve; 02.09.2016
comment
Чтобы избежать очень длинного ключа, используйте этот SELECT EXISTS(SELECT 1 FROM table1 WHERE ...) as 'is_exist' - person Rahul Saini; 25.06.2019

Недавно я провел несколько исследований на эту тему. Способ реализации должен быть другим, если поле является ТЕКСТОВЫМ, а не уникальным полем.

Я провел несколько тестов с полем ТЕКСТ. Учитывая тот факт, что у нас есть таблица с 1M записей. 37 записей равны "чему-то":

  • SELECT * FROM test WHERE text LIKE '%something%' LIMIT 1 с mysql_num_rows(): 0,039061069488525s. (БЫСТРЕЕ)
  • SELECT count(*) as count FROM test WHERE text LIKE '%something% : 16.028197050095s.
  • SELECT EXISTS(SELECT 1 FROM test WHERE text LIKE '%something%') : 0.87045907974243s.
  • SELECT EXISTS(SELECT 1 FROM test WHERE text LIKE '%something%' LIMIT 1) : 0.044898986816406s.

Но теперь с полем BIGINT PK только одна запись равна 321321:

  • SELECT * FROM test2 WHERE id ='321321' LIMIT 1 с mysql_num_rows(): 0.0089840888977051s.
  • SELECT count(*) as count FROM test2 WHERE id ='321321' : 0.00033879280090332s.
  • SELECT EXISTS(SELECT 1 FROM test2 WHERE id ='321321') : 0.00023889541625977s.
  • SELECT EXISTS(SELECT 1 FROM test2 WHERE id ='321321' LIMIT 1): 0,00020313262939453s. (БЫСТРЕЕ)
person Laurent W.    schedule 21.05.2012
comment
Спасибо за дополнительный ответ. Считаете ли вы, что разница во времени между двумя самыми быстрыми вариантами поля ТЕКСТ достаточно согласована? Разница не кажется большой, и использование SELECT EXISTS (SELECT 1 ... LIMIT 1) кажется неплохим в обоих случаях. - person Bernard Chen; 22.05.2012
comment
Вы правы, по остальным результатам, касающимся текстового поля, разница не так важна. Тем не менее, возможно, запрос лучше использовать SELECT 1 FROM test WHERE texte LIKE '%something%' LIMIT 1 - person Laurent W.; 05.06.2012
comment
Я пробовал mysql, и в случае, если вы используете select 1 ... limit 1, бесполезно окружать select exists - person Adrien Horgnies; 15.05.2016
comment
@LittleNooby есть разница. SELECT EXISTS ... дает истинное и ложное значение (1 или 0), а SELECT 1 ... дает либо 1, либо пусто. Есть тонкая разница между ложным значением и пустым набором, в зависимости от вашей ситуации. - person Quickpick; 18.05.2016
comment
@LittleNooby - отличный аргумент, который легко упустить из виду. В приведенных выше тестах синхронизации отсутствует SELECT 1 FROM test WHERE ... без SELECT EXISTS вокруг него. По-видимому, так будет на волосок быстрее. - person ToolmakerSteve; 02.09.2016
comment
Я считаю, что SELECT * ... становится медленнее по мере добавления дополнительных столбцов. Мне было бы любопытно, как все это соотносится с SELECT _1 _... - person Nosajimiki; 13.07.2017
comment
Это почти наверняка потому, что выбор PK может быть удовлетворен индексом для SELECT 1, но не для SELECT *, который требует поиска по строке. Выбор ТЕКСТА требует поиска строки в любом случае из-за условия. SELECT 1 FROM ... WHERE ... LIMIT 1 предоставит вам лучшее из обоих миров .. добавьте обертку EXISTS, если вам требуется логический возврат для отсутствия совпадающих строк. - person Arth; 10.09.2018
comment
Какую версию MySQL вы использовали? По крайней мере, в 5.5+ нет разницы между EXISTS (SELECT ...) и EXISTS (SELECT ... LIMIT 1). MySQL достаточно умен, чтобы вставить этот LIMIT 1 сам по себе, потому что EXISTS работает так: он останавливается, когда найден хотя бы один результат. - person Ruslan Stelmachenko; 29.01.2020

Краткий пример ответа @CrisThompson

Пример:

mysql> SELECT * FROM table_1;
+----+--------+
| id | col1   |
+----+--------+
|  1 | foo    |
|  2 | bar    |
|  3 | foobar |
+----+--------+
3 rows in set (0.00 sec)

mysql> SELECT EXISTS(SELECT 1 FROM table_1 WHERE id = 1);
+--------------------------------------------+
| EXISTS(SELECT 1 FROM table_1 WHERE id = 1) |
+--------------------------------------------+
|                                          1 |
+--------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT EXISTS(SELECT 1 FROM table_1 WHERE id = 9);
+--------------------------------------------+
| EXISTS(SELECT 1 FROM table_1 WHERE id = 9) |
+--------------------------------------------+
|                                          0 |
+--------------------------------------------+
1 row in set (0.00 sec)

Используя псевдоним:

mysql> SELECT EXISTS(SELECT 1 FROM table_1 WHERE id = 1) AS mycheck;
+---------+
| mycheck |
+---------+
|       1 |
+---------+
1 row in set (0.00 sec)
person jaltek    schedule 19.12.2013
comment
Хотя принятый ответ был полезен, мне понравился синтаксис псевдонима. Спасибо! - person krummens; 15.03.2021

В своих исследованиях я могу найти результат, набирающий скорость.

select * from table where condition=value
(1 total, Query took 0.0052 sec)

select exists(select * from table where condition=value)
(1 total, Query took 0.0008 sec)

select count(*) from table where condition=value limit 1) 
(1 total, Query took 0.0007 sec)

select exists(select * from table where condition=value limit 1)
(1 total, Query took 0.0006 sec) 
person shihab mm    schedule 15.02.2017
comment
Эти числа бессмысленны, если вы не полностью контролируете вселенную. Во-первых, попробуйте сделать их в обратном порядке. Если, конечно, ваша точка зрения не имеет значения. В таком случае вы, вероятно, правы. - person theking2; 17.06.2021

Я считаю, что стоит отметить, хотя это было затронуто в комментариях, что в этой ситуации:

SELECT 1 FROM my_table WHERE *indexed_condition* LIMIT 1

Превосходит:

SELECT * FROM my_table WHERE *indexed_condition* LIMIT 1

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

Добавление предложения LIMIT позволяет машине останавливаться после обнаружения любой строки.

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

SELECT EXISTS(SELECT * FROM my_table WHERE *indexed_condition*)

Это отправляет те же сигналы в движок (1 / * здесь не имеет значения), но я бы все равно написал 1, чтобы закрепить привычку при использовании EXISTS:

SELECT EXISTS(SELECT 1 FROM my_table WHERE *indexed_condition*)

Может иметь смысл добавить обертку EXISTS, если вам требуется явный возврат при отсутствии совпадений строк.

person Arth    schedule 08.03.2017

Предлагаем вам не использовать Count, потому что count всегда создает дополнительную нагрузку для использования db SELECT 1 и возвращает 1, если ваша запись прямо здесь, в противном случае он возвращает null, и вы можете справиться с этим.

person Fatih Karatana    schedule 02.11.2012

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

person jaywon    schedule 04.11.2009
comment
Однако это специфично для БД. COUNT (*), как известно, работает медленно в PostgreSQL. Лучше было бы выбрать столбец PK и посмотреть, возвращает ли он какие-либо строки. - person BalusC; 05.11.2009
comment
COUNT (*) работает медленно в InnoDB, хотя - person Will; 22.06.2012

Иногда бывает очень удобно получить первичный ключ автоматического увеличения (id) строки, если он существует, и 0, если нет.

Вот как это можно сделать с помощью одного запроса:

SELECT IFNULL(`id`, COUNT(*)) FROM WHERE ...
person Zaxter    schedule 22.03.2016
comment
Почему бы просто не использовать здесь IFNULL(id, 0) вместо COUNT(*)? - person Ethan Hohensee; 28.08.2017

Для таблиц, отличных от InnoDB, вы также можете использовать таблицы информационной схемы:

http://dev.mysql.com/doc/refman/5.1/en/tables-table.html

person davek    schedule 04.11.2009

Я бы пошел с COUNT(1). Это быстрее, чем COUNT(*), потому что COUNT(*) проверяет, равен ли хотя бы один столбец в этой строке! = NULL. Вам это не нужно, особенно потому, что у вас уже есть условие (предложение WHERE). COUNT(1) вместо этого проверяет действительность 1, которая всегда действительна и требует гораздо меньше времени для проверки.

person Felix    schedule 04.11.2009
comment
-1 Это неправильно. COUNT (*) не смотрит на значения столбцов - он просто подсчитывает количество строк. См. Мой ответ здесь: http://stackoverflow.com/questions/2876909/count-and-countcolumn-name-whats-the-diff - person Mark Byers; 29.05.2010
comment
COUNT () намного медленнее, чем EXISTS, поскольку EXISTS может возвращать, когда впервые находит строку - person Will; 22.06.2012

Или вы можете вставить необработанную часть sql в условия, чтобы у меня было 'conditions' => array ('Member.id NOT IN (SELECT Membership.member_id FROM memberships AS Membership)')

person user4193303    schedule 29.10.2014

COUNT(*) оптимизированы в MySQL, поэтому первый запрос, вообще говоря, будет быстрее.

person Arthur Reutenauer    schedule 04.11.2009
comment
Вы имеете в виду оптимизацию MyISAM для выбора счетчика для всей таблицы? Я не думал, что это поможет, если будет условие WHERE. - person Bernard Chen; 05.11.2009