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

281

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

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

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

SELECT * FROM table1 WHERE ... LIMIT 1

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

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

Теги:
performance
exists

13 ответов

403
Лучший ответ

Вы также можете попробовать использовать

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

per документация

За комментарий ниже:

SELECT EXISTS(SELECT 1 FROM table1 WHERE ...)
  • 27
    Тест с ...EXISTS( SELECT 1/0 FROM someothertable) . Для SQL Server и Oracle - нет разницы, использовать *, 1 или NULL, потому что EXISTS проверяет только логическое значение на основе 1+ соответствия критерия WHERE.
  • 73
    Ребята, прямо в документации, связанной с этим ответом, во втором абзаце, говорится: «Традиционно подзапрос EXISTS начинается с SELECT *, но он может начинаться с SELECT 5 или SELECT column1 или чего-либо еще. MySQL игнорирует список SELECT в таком случае. подзапрос, так что это не имеет значения ".
Показать ещё 6 комментариев
158

Недавно я провел несколько исследований по этому вопросу. Способ реализовать его должен быть другим, если поле является полем TEXT, не уникальным полем.

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

  • SELECT * FROM test WHERE texte 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. (БЫСТРЕЕ)
  • 1
    Спасибо за дополнительный ответ. Считаете ли вы разницу во времени между двумя самыми быстрыми вариантами для поля TEXT довольно последовательной? Разница не кажется большой, и использование SELECT EXISTS (SELECT 1 ... LIMIT 1) кажется довольно хорошим в обоих случаях.
  • 1
    Вы правы, разница не так важна в отношении других результатов, касающихся текстового поля. Тем не менее, возможно, запрос будет лучше, если использовать SELECT 1 FROM test WHERE texte LIKE '%something%' LIMIT 1
Показать ещё 5 комментариев
21

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

Пример:

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)
7

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

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) 
4

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

3

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

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 если вам требуется явный возврат, когда ни одна строка не совпадает.

2

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

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

SELECT IFNULL(`id`, COUNT(*)) FROM WHERE ...
  • 0
    Почему бы просто не использовать здесь IFNULL(id, 0) вместо COUNT(*) ?
1

Производительность также зависит от ваших табличных индексов. Иногда лучше использовать старые способы с правильным индексом таблицы:

SELECT COUNT(field) FROM table WHERE field = 'something' LIMIT 1  

Введите индекс "my_index" в поле "<" >

Объяснение будет выглядеть следующим образом:

id select_type table  type   possible_keys key       key_len  ref   rows Extra
1  SIMPLE      table  ref    my_index      my_index  4        const 1  Using index
0

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

0

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

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

0

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

  • 8
    -1 Это неправильно. COUNT (*) не смотрит на значения столбца - он просто считает количество строк. Смотрите мой ответ здесь: stackoverflow.com/questions/2876909/…
  • 6
    COUNT () намного медленнее, чем EXISTS, поскольку EXISTS может возвращаться, когда он впервые находит строку
0

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

  • 4
    Это, однако, специфично для БД. Известно, что COUNT (*) работает медленно в PostgreSQL. Лучше было бы выбрать столбец PK и посмотреть, возвращает ли он какие-либо строки.
  • 3
    COUNT (*) работает медленно в InnoDB
-3

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

  • 2
    Вы имеете в виду оптимизацию, которую имеет MyISAM для выбора счетчика для всей таблицы? Я не думаю, что это помогло, если бы было состояние ГДЕ.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню