Просто интересно, если кто-то из вас использует Count(1)
слишком много, Count(*)
и есть ли заметная разница в производительности или это просто унаследованная привычка, появившаяся в прошлом?
Конкретная база данных есть SQL Server 2005
.
sql
sql-server
performance
super9
источник
источник
COUNT(*)
противCOUNT(1)
противCOUNT(pk)
- что лучше? , Там тожеCOUNT(*)
противCOUNT(column-name)
- что правильнее? , Там вполне могут быть другие дубликаты.Ответы:
Нет никакой разницы.
Причина:
«1» является ненулевым выражением: так же, как и
COUNT(*)
. Оптимизатор распознает его таким, какой он есть: тривиальным.Так же, как
EXISTS (SELECT * ...
илиEXISTS (SELECT 1 ...
Пример:
Тот же IO, тот же план, работает
Редактировать, август 2011
Похожий вопрос на DBA.SE .
Редактировать, декабрь 2011
COUNT(*)
упоминается конкретно в ANSI-92 (ищите "Scalar expressions 125
")То есть стандарт ANSI признает, что это очевидно, что вы имеете в виду.
COUNT(1)
было оптимизировано поставщиками СУБД из- за этого суеверия. В противном случае это будет оцениваться в соответствии с ANSIисточник
В SQL Server эти операторы дают одинаковые планы.
Вопреки распространенному мнению, в Oracle они тоже.
SYS_GUID()
в Oracle довольно интенсивные вычисления.В моей тестовой базе данных
t_even
есть таблица со1,000,000
строкамиЭтот запрос:
выполняется в течение
48
нескольких секунд, так как функция должна оценивать каждоеSYS_GUID()
возвращаемое значение, чтобы убедиться, что оно не являетсяNULL
.Тем не менее, этот запрос:
работает в течение
2
нескольких секунд, так как он даже не пытается оценитьSYS_GUID()
(несмотря на то,*
что аргументCOUNT(*)
)источник
SYS_GUID()
по крайней мере (я имею в виду, точно) один раз для подзапроса, чтобы вернуть результат, верно?COUNT(*)
зависит от значенийSYS_GUID
?COUNT(*)
запуска ему нужна таблица, поэтому подзапрос должен действовать как один. В противном случае я не вижу способаCOUNT(*)
вернуть значимое значениеmap
метод, вы видите, как эти два выражения:t_even.map(() => sys_guid()).length
иt_even.length
всегда будут возвращать одно и то же значение? Оптимизатор Oracle достаточно умен, чтобы увидеть и оптимизироватьmap
часть.length
не совсем зависит от того, из чего состоит коллекция, только от количества ее элементов. Если это число хранится в метаданных коллекции (это не относится к Oracle или большинству других современных СУБД, но относится к старому механизму хранения MySQL, MyISAM), тогдаCOUNT(*)
просто нужно взять значение из метаданных.Понятно
COUNT(*)
и всегдаCOUNT(1)
будет возвращать один и тот же результат. Поэтому, если бы один был медленнее другого, это было бы эффективно из-за ошибки оптимизатора. Поскольку обе формы очень часто используются в запросах, для СУБД не имеет смысла оставлять такую ошибку незафиксированной. Следовательно, вы обнаружите, что производительность обеих форм (вероятно) одинакова во всех основных СУБД SQL.источник
Я работаю в команде SQL Server и, надеюсь, могу уточнить некоторые моменты в этой теме (я раньше этого не видел, поэтому мне жаль, что команда разработчиков не сделала этого раньше).
Во- первых, не существует семантическая разница между
select count(1) from table
VS.select count(*) from table
. Они возвращают одинаковые результаты во всех случаях (и это ошибка, если нет). Как отмечено в других ответах,select count(column) from table
семантически отличается и не всегда возвращает те же результаты, что иcount(*)
.Во-вторых, в отношении производительности в SQL Server (и в SQL Azure) могут иметь значение два аспекта: работа во время компиляции и работа во время выполнения. Работа во время компиляции - это незначительный объем дополнительной работы в текущей реализации. В некоторых случаях расширение * распространяется на все столбцы, после чего выводится обратно до 1 столбца, выводимого из-за того, как некоторые из внутренних операций работают при связывании и оптимизации. Я сомневаюсь, что это проявится в любом измеримом тесте и, вероятно, затеряется в шуме всех других вещей, которые происходят под прикрытием (таких как автостатистика, сеансы xevent, накладные расходы хранилища запросов, триггеры и т. Д.). Это может быть несколько тысяч дополнительных инструкций процессора. Так, count (1) выполняет чуть меньше работы во время компиляции (что обычно происходит один раз, и план кэшируется в нескольких последующих выполнениях). Что касается времени выполнения, при условии, что планы одинаковы, не должно быть никакой измеримой разницы. (Один из предыдущих примеров показывает разницу - скорее всего, из-за других факторов на машине, если план такой же).
Что касается того, как план может потенциально отличаться. Это крайне маловероятно, но это потенциально возможно в архитектуре текущего оптимизатора. Оптимизатор SQL Server работает как поисковая программа (представьте: компьютерная программа, играющая в шахматы, ищущая различные альтернативы для разных частей запроса и оценивающая альтернативы, чтобы найти самый дешевый план за разумное время). Этот поиск имеет несколько ограничений на то, как он работает, чтобы компиляция запросов заканчивалась в разумные сроки. Для запросов, выходящих за рамки тривиальных, существуют фазы поиска, и они имеют дело с траншами запросов, основанными на том, насколько дорогостоящим оптимизатор считает, что запрос потенциально может выполняться. Существует 3 основных этапа поиска, и каждый этап может использовать более агрессивную (дорогую) эвристику, пытаясь найти более дешевый план, чем любое предыдущее решение. В конце концов, в конце каждой фазы происходит процесс принятия решения, который пытается определить, должен ли он вернуть план, который он нашел до сих пор, или должен продолжать поиск. В этом процессе используется общее время, затраченное на данный момент, в сравнении с оценочной стоимостью лучшего плана, найденного на данный момент. Таким образом, на разных машинах с разными скоростями ЦП возможно (хотя и редко) получить разные планы из-за тайм-аута на более ранней стадии с планом по сравнению с переходом на следующую фазу поиска. Есть также несколько похожих сценариев, связанных с тайм-аутом последней фазы и, возможно, нехваткой памяти для очень и очень дорогих запросов, которые занимают всю память на машине (обычно это не проблема для 64-битных систем, но это была большая проблема). назад на 32-битных серверах). В конечном итоге, если вы получите другой план, производительность во время выполнения будет отличаться. Я не
Net-net: Пожалуйста, используйте любой из двух вариантов, который вам нужен, поскольку в практической форме это не имеет значения. (Честно говоря, существует гораздо более значительный фактор, влияющий на производительность в SQL).
Надеюсь, это поможет. Я написал главу книги о том, как работает оптимизатор, но я не знаю, уместно ли размещать его здесь (так как я все еще верю, что я получаю от него небольшие гонорары). Поэтому вместо публикации я опубликую ссылку на выступление, которое я дал на SQLBits в Великобритании, о том, как оптимизатор работает на высоком уровне, чтобы вы могли более подробно рассмотреть различные основные этапы поиска, если хотите. чтобы узнать об этом. Вот ссылка на видео: https://sqlbits.com/Sessions/Event6/inside_the_sql_server_query_optimizer
источник
1
также подвергается такой же экспансии. Я основываю это на тестах производительности здесь stackoverflow.com/questions/1597442/… также вижу пример в этом ответе на запрос, использующий1
неожиданный сбой, когда разрешения на уровне столбца находятся в игреВ стандарте SQL-92
COUNT(*)
конкретно означает «мощность выражения таблицы» (это может быть базовая таблица, `VIEW, производная таблица, CTE и т. Д.).Я думаю, что идея была в том, что
COUNT(*)
легко разобрать. Использование любого другого выражения требует, чтобы синтаксический анализатор не ссылался ни на какие столбцы (COUNT('a')
гдеa
литерал, аCOUNT(a)
гдеa
столбец, может давать разные результаты).В том же духе,
COUNT(*)
может быть легко выбран человеком-программистом, знакомым со стандартами SQL, что является полезным навыком при работе с предложениями SQL более одного поставщика.Кроме того, в особом случае
SELECT COUNT(*) FROM MyPersistedTable;
, думая, что СУБД, скорее всего, будет хранить статистику по количеству элементов таблицы.Поэтому, поскольку
COUNT(1)
иCOUNT(*)
семантически эквивалентны, я используюCOUNT(*)
.источник
COUNT(*)
иCOUNT(1)
одинаковы в случае результата и производительности.источник
Я ожидаю, что оптимизатор обеспечит отсутствие реальной разницы за пределами странных крайних случаев.
Как и во всем, единственный реальный способ сказать, это измерить ваши конкретные случаи.
Тем не менее, я всегда использовал
COUNT(*)
.источник
Поскольку этот вопрос возникает снова и снова, вот еще один ответ. Я надеюсь добавить кое-что новичкам, интересующимся «лучшей практикой» здесь.
SELECT COUNT(*) FROM something
считает записи, что является легкой задачей.SELECT COUNT(1) FROM something
извлекает 1 для каждой записи, а затем подсчитывает 1, которые не равны нулю, что, по сути, является подсчетом записей, только более сложным.Сказав это: «Хороший БД замечает, что второе утверждение приведет к тому же счету, что и первое утверждение, и изменит его соответствующим образом, чтобы не выполнять ненужную работу. Поэтому обычно оба оператора приводят к одному и тому же плану выполнения и занимают одинаковое количество времени.
Однако с точки зрения читабельности вы должны использовать первое утверждение. Вы хотите считать записи, поэтому считайте записи, а не выражения. Используйте COUNT (выражение) только тогда, когда вы хотите сосчитать ненулевые вхождения чего-либо.
источник
Я провел быстрый тест на SQL Server 2012 на блоке hyper-v 8 ГБ ОЗУ. Вы можете увидеть результаты для себя. Во время выполнения этих тестов я не запускал никаких других оконных приложений, кроме SQL Server Management Studio.
Моя схема таблицы:
Общее количество записей в
Employee
таблице: 178090131 (~ 178 миллионов строк)Первый запрос:
Результат первого запроса:
Второй запрос:
Результат второго запроса:
Вы можете заметить, что есть разница в 83 (= 70265 - 70182) миллисекунды, которые можно легко отнести к точному состоянию системы во время выполнения запросов. Также я сделал один прогон, так что эта разница станет более точной, если я сделаю несколько прогонов и сделаю некоторое усреднение. Если для такого огромного набора данных разница составляет менее 100 миллисекунд, то мы можем легко заключить, что два запроса не имеют никакой разницы в производительности, демонстрируемой механизмом SQL Server.
Примечание. В обоих случаях ОЗУ достигает 100% использования. Я перезапустил службу SQL Server перед запуском обоих прогонов.
источник
Я запускал это сотни раз, каждый раз очищая кэш. Результаты время от времени меняются по мере изменения нагрузки на сервер, но почти всегда
count(*)
имеют большее время процессора.источник
count(*)
иcount(1)
возвращать результаты в течение нескольких мс друг от друга, даже при подсчете таблицы с 4,5 миллионами строк, в моем экземпляре SQL 2008.Существует статья показывает , что
COUNT(1)
на Oracle это просто псевдонимCOUNT(*)
, с доказательством об этом.Я процитирую некоторые части:
С пользователями с
ALTER SESSION
привилегией, вы можете положитьtracefile_identifier
, включите трассировку оптимизатора и запускCOUNT(1)
выберите, как:SELECT /* test-1 */ COUNT(1) FROM employees;
.После этого вам нужно локализовать файлы трассировки, что можно сделать
SELECT VALUE FROM V$DIAG_INFO WHERE NAME = 'Diag Trace';
. Позже в файле вы найдете:Как видите, это просто псевдоним для
COUNT(*)
.Еще один важный комментарий: два десятилетия назад в Oracle
COUNT(*)
было намного быстрее , чем в Oracle 7.3:Для других баз данных, таких как Sql Server, их следует исследовать отдельно для каждой.
Я знаю, что этот вопрос специфичен для Sql Server, но другие вопросы по SO по той же теме, не говоря уже о базе данных, были закрыты и помечены как дублированные из этого ответа.
источник
Во всех СУБД оба способа подсчета эквивалентны с точки зрения того, какой результат они производят. Что касается производительности, я не заметил каких-либо различий в производительности в SQL Server, но, возможно, стоит отметить, что некоторые СУБД, например PostgreSQL 11, имеют менее оптимальные реализации,
COUNT(1)
поскольку они проверяют обнуляемость выражения аргумента, как можно увидеть в этом посте .Я обнаружил, что при работе с 1М строк разница в производительности составляет 10%:
источник
COUNT (1) существенно не отличается от COUNT (*), если вообще. Что касается вопроса о СЧЕТАХ НЕДОПУСТИМЫХ КОЛОННАХ, это может быть просто продемонстрировать разницу между COUNT (*) и COUNT (<some col>) -
источник