Count (*) vs Count (1) - SQL Server
просто интересно, если кто-нибудь из вас использовать Count(1)
над Count(*)
и если есть заметная разница в производительности или если это просто устаревшая привычка, которая была перенесена из дней прошедших?
(конкретная база данных SQL Server 2005
.)
11 ответов
нет никакой разницы.
причина:
книги-лайн говорит:"
COUNT ( { [ [ ALL | DISTINCT ] expression ] | * } )
"
" 1 " является ненулевым выражением: так что это то же самое, что COUNT(*)
.
Оптимизатор распознает его таким, какой он есть: тривиальным.
аналогично EXISTS (SELECT * ...
или EXISTS (SELECT 1 ...
пример:
SELECT COUNT(1) FROM dbo.tab800krows
SELECT COUNT(1),FKID FROM dbo.tab800krows GROUP BY FKID
SELECT COUNT(*) FROM dbo.tab800krows
SELECT COUNT(*),FKID FROM dbo.tab800krows GROUP BY FKID
тот же IO, тот же план, работы
Edit, Aug 2011
Edit, Dec 2011
COUNT(*)
упоминается конкретно в в ANSI-92 (ищите "Scalar expressions 125
")
корпус:
a) если указан COUNT (*), то результатом является мощность T.
то есть, стандарт ANSI распознает его как кровотечение очевидно, что вы имеете в виду. COUNT(1)
был оптимизирован поставщиками РСУБД , потому что этого суеверия. В противном случае оцениваться согласно ANSI
b) в противном случае пусть TX-таблица с одним столбцом, которая является результат применения выражения
к каждой строке T и устранение нулевых значений. Если одно или несколько значений null исключено, затем поднимается условие завершения: предупреждение -
в SQL Server эти операторы дают те же планы.
Вопреки распространенному мнению, в Oracle они тоже.
SYS_GUID()
в Oracle довольно интенсивная функция вычисления.
в моей тестовой базы данных, t_even
в таблице 1,000,000
строки
запрос:
SELECT COUNT(SYS_GUID())
FROM t_even
работает 48
секунд, так как функция должна оценивать каждый SYS_GUID()
вернулся, чтобы убедиться, что это не NULL
.
однако этот запрос:
SELECT COUNT(*)
FROM (
SELECT SYS_GUID()
FROM t_even
)
работает, а 2
секунд, так как он даже не пытаются оценить SYS_GUID()
(несмотря на *
будучи аргумент COUNT(*)
)
ясно, COUNT (*) и COUNT(1) будет всегда верните тот же результат. Поэтому, если бы один был медленнее, чем другой, это было бы эффективно из-за ошибки оптимизатора. Поскольку обе формы очень часто используются в запросах, СУБД не имеет смысла оставлять такую ошибку незафиксированной. Следовательно, вы обнаружите, что производительность обеих форм (вероятно) одинакова во всех основных СУБД SQL.
в стандарте SQL-92, COUNT(*)
в частности означает "мощность табличного выражения" (может быть базовой таблицей, `VIEW, производной таблицей, CTE и т. д.).
Я думаю, идея была в том, что COUNT(*)
легко разобрать. Использование любого другого выражения требует от парсера убедиться, что он не ссылается на какие-либо столбцы (COUNT('a')
здесь a
является буквальным и COUNT(a)
здесь a
столбец может давать разные результаты).
в том же духе COUNT(*)
можно легко подобрать из человеческого кодера, знакомого со стандартами SQL, полезный навык при работе с более чем одним предложением SQL поставщика.
кроме того, в частном случае SELECT COUNT(*) FROM MyPersistedTable;
, думая, что СУБД, вероятно, будет содержать статистику для мощности таблицы.
COUNT(1)
и COUNT(*)
семантически эквивалентны, я использую COUNT(*)
.Я ожидал бы, что оптимизатор обеспечит отсутствие реальной разницы за пределами странных крайних случаев.
Как и в любом случае, единственный реальный способ сказать-это измерить ваши конкретные случаи.
тем не менее, я всегда использовал COUNT(*)
.
поскольку этот вопрос возникает снова и снова, вот еще один ответ. Я надеюсь добавить что-то для начинающих, интересующихся "лучшей практикой" здесь.
SELECT COUNT(*) FROM something
подсчитывает записи, что является легкой задачей.
SELECT COUNT(1) FROM something
извлекает 1 на запись и чем подсчитывает 1s, которые не являются нулевыми, что по существу подсчет записей, только сложнее.
сказав это: хорошая СУБД заметит, что второй оператор приведет к тому же количеству, что и первый заявление и заново интерпретировать его соответствующим образом, а не делать ненужную работу. Поэтому обычно оба оператора приводят к одному и тому же плану выполнения и занимают одинаковое количество времени.
однако с точки зрения читаемости вы должны использовать первый оператор. Вы хотите считать записи, поэтому считайте записи, а не выражения. Используйте COUNT (expression) только тогда, когда вы хотите подсчитать ненулевые случаи чего-либо.
Я провел быстрый тест на SQL Server 2012 на 8 ГБ оперативной памяти hyper-V. Вы можете сами увидеть результаты. Во время выполнения этих тестов я не запускал никаких других оконных приложений, кроме SQL Server Management Studio.
моя схема таблицы:
CREATE TABLE [dbo].[employee](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NOT NULL,
CONSTRAINT [PK_employee] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
общее количество записей в Employee
таблица: 178090131 (~ 178 миллионов строк)
Первый Запрос:
Set Statistics Time On
Go
Select Count(*) From Employee
Go
Set Statistics Time Off
Go
результат первого Запрос:
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 35 ms.
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 10766 ms, elapsed time = 70265 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
Второй Запрос:
Set Statistics Time On
Go
Select Count(1) From Employee
Go
Set Statistics Time Off
Go
результат второго запроса:
SQL Server parse and compile time:
CPU time = 14 ms, elapsed time = 14 ms.
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 11031 ms, elapsed time = 70182 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
вы можете заметить, что есть разница в 83 (=70265 - 70182) миллисекунды, которые можно легко отнести к точному состоянию системы во время выполнения запросов. Также я сделал один прогон, поэтому эта разница станет более точной, если я сделаю несколько прогонов и сделаю некоторое усреднение. Если для такого огромного набора данных, разница идет менее 100 миллисекунд, то мы можем легко сделать вывод, что два запроса не имеют никакой разницы в производительности, отображаемой SQL Server Engine.
Примечание : ОЗУ попадает близко к 100% использования в обоих запусках. Перед запуском обоих запусков я перезапустил службу SQL Server.
SET STATISTICS TIME ON
select count(1) from MyTable (nolock) -- table containing 1 million records.
время выполнения SQL Server:
Время процессора = 31 МС, прошедшее время = 36 МС.
select count(*) from MyTable (nolock) -- table containing 1 million records.
время выполнения SQL Server:
Время процессора = 46 МС, прошедшее время = 37 МС.
я запускал это сотни раз, очищая кэш каждый раз.. Результаты меняются время от времени, поскольку нагрузка на сервер меняется, но почти всегда count(*) имеет более высокое время процессора.
есть статьи показывал, что COUNT(1)
on Оракул - это просто псевдоним COUNT(*)
С доказательство об этом.
я процитирую некоторые части:
есть часть программного обеспечения базы данных, которая называется " Оптимизатор", который определяется в официальной документации как "Встроенное программное обеспечение базы данных, которое определяет наиболее эффективный способ выполните инструкцию SQL".
один из компонентов оптимизатора называется " трансформатор", чья роль заключается в том, чтобы определить, выгодно ли переписывать исходный оператор SQL в семантически эквивалентный оператор SQL это было бы более эффективно.
хотите посмотреть, что оптимизатор делает при написании запроса используя COUNT (1)?
С пользователем с ALTER SESSION
привилегии, вы можете поставить tracefile_identifier
, включите трассировку оптимизатора и запустите COUNT(1)
выберите, как: SELECT /* test-1 */ COUNT(1) FROM employees;
.
после этого, нужно локализовать файлы трассировки, что можно сделать с помощью SELECT VALUE FROM V$DIAG_INFO WHERE NAME = 'Diag Trace';
. Позже в файле вы найдете:
SELECT COUNT(*) “COUNT(1)” FROM “COURSE”.”EMPLOYEES” “EMPLOYEES”
как вы можете видеть, это просто псевдоним для COUNT(*)
.
еще один важный комментарий:COUNT(*)
действительно быстрее двадцать лет назад на Oracle, перед Oracle 7.3:
Count (1) был переписан в count (*) с 7.3, потому что Oracle нравится к Автоматическая настройка мифических утверждений. В более раннем Oracle7 oracle должна была вычислить (1) для каждой строки как функцию перед детерминированным и Недетерминированные существуют.
Итак, два десятилетия назад count (*) был быстрее
для других баз данных, как Sql Server, он должен быть исследован индивидуально для каждого из них.
Я знаю, что этот вопрос специфичен для Sql Server, но другие вопросы по SO по той же теме, без упоминания базы данных, был закрыт и помечен как дублированный из этого ответа.
легкий для того чтобы демо-счет(*) против графа()--
USE tempdb;
GO
IF OBJECT_ID( N'dbo.Blitzen', N'U') IS NOT NULL DROP TABLE dbo.Blitzen;
GO
CREATE TABLE dbo.Blitzen (ID INT NULL, Somelala CHAR(1) NULL);
INSERT dbo.Blitzen SELECT 1, 'A';
INSERT dbo.Blitzen SELECT NULL, NULL;
INSERT dbo.Blitzen SELECT NULL, 'A';
INSERT dbo.Blitzen SELECT 1, NULL;
SELECT COUNT(*), COUNT(1), COUNT(ID), COUNT(Somelala) FROM dbo.Blitzen;
GO
DROP TABLE dbo.Blitzen;
GO