Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
SELECT COUNT_BIG(*) FROM t1
SELECT COUNT_BIG(1) FROM t1
Table 't1'. Scan count 6, logical reads 114911, physical reads 0, ....
SQL Server Execution Times:
CPU time = 2673 ms, elapsed time = 1787 ms.
Table 't1'. Scan count 6, logical reads 114911, physical reads 0, ....
SQL Server Execution Times:
CPU time = 2625 ms, elapsed time = 1878 ms.
DECLARE @t TABLE (a INT)
INSERT INTO @t (a) VALUES (1), (2), (3), (NULL)
SELECT AVG(a), COUNT(*), COUNT(a)
FROM @t
SELECT AVG(a)
FROM (VALUES(1), (2)) t(a)
В случае если нужно проверить наличие записей в таблице, то использование метаданных как было показано выше не даст особых преимуществ…
IF OBJECT_ID('dbo.test', 'U') IS NOT NULL
DROP TABLE dbo.test
GO
;WITH E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
, E2(N) AS (SELECT 1 FROM E1 a, E1 b)
, E4(N) AS (SELECT 1 FROM E2 a, E2 b)
, E8(N) AS (SELECT 1 FROM E4 a, E4 b)
SELECT val = 1
INTO dbo.test
FROM E8
IF EXISTS(SELECT * FROM dbo.test)
PRINT 1
IF EXISTS(
SELECT *
FROM sys.dm_db_partition_stats
WHERE [object_id] = OBJECT_ID('dbo.test')
AND row_count > 0
AND index_id < 2
) PRINT 1
TRUNCATE TABLE dbo.test
--DELETE TOP(50) PERCENT FROM dbo.test
IF EXISTS(SELECT * FROM dbo.test)
PRINT 1
IF EXISTS(
SELECT *
FROM sys.dm_db_partition_stats
WHERE [object_id] = OBJECT_ID('dbo.test')
AND row_count > 0
AND index_id < 2
) PRINT 1


Когда нужно проверить есть ли записи в таблице — разницы нет, какой подход применять.
Да, еще я часто встречал такой способ «SELECT TOP 1 1 FROM Table», как насчет него?
SELECT TOP 1 1
FROM Sales.SalesOrderDetail
SELECT 1
WHERE EXISTS(
SELECT *
FROM Sales.SalesOrderDetail
)
Table 'SalesOrderDetail'. Scan count 1, logical reads 2, physical reads 0, ...
SQL Server Execution Times:
CPU time = 5 ms, elapsed time = 5 ms.
Table 'SalesOrderDetail'. Scan count 1, logical reads 2, physical reads 0, ...
SQL Server Execution Times:
CPU time = 4 ms, elapsed time = 6 ms.
а) если метаданные для таблицы содержатНе понял, что если?
use test_dev;
go
if object_id('T4', 'U') is not null
drop table T4;
create table T4 (
ID int
, Data varchar(500)
);
with V as (
select 1 as N
union all
select N+1 from V
where N < 10000
)
insert into T4 (Data)
select cast(replicate(ltrim(str(n)), 100) as varchar(500)) as data from V
option (maxrecursion 0)
;
(строк обработано: 10000)
select 1 where exists (select * from T4);
select top 1 1 from T4;
if exists(select 1 from t4) print 1;
-----------
1
(строк обработано: 1)
-----------
1
(строк обработано: 1)
1
select
cast(object_name(object_id) as varchar(20)) as object_name
,object_id
,used_page_count
,row_count
from sys.dm_db_partition_stats t
where object_id = object_id('T4')
;
select
cast(replace(substring(s2.text, statement_start_offset / 2+1 ,
( (case when statement_end_offset = -1
then (len(convert(nvarchar(max),s2.text)) * 2)
else statement_end_offset end) - statement_start_offset) / 2+1), char(13)+char(10), ' ') as varchar(50)) as sql_statement
,execution_count
,last_physical_reads
,last_logical_reads
,last_logical_writes
,last_elapsed_time
from sys.dm_exec_query_stats as s1
cross apply sys.dm_exec_sql_text(sql_handle) as s2
where s2.objectid is null
order by s1.sql_handle, s1.statement_start_offset, s1.statement_end_offset
;
object_name object_id used_page_count row_count
-------------------- ----------- -------------------- --------------------
T4 741577680 514 10000
(строк обработано: 1)
sql_statement execution_count last_physical_reads last_logical_reads last_logical_writes last_elapsed_time
-------------------------------------------------- -------------------- -------------------- -------------------- -------------------- --------------------
select cast(object_name(object_id) as varchar(20 1 0 2 0 0
with V as ( select 1 as N union all select N+1 1 0 106953 505 204012
select 1 where exists (select * from T4); 1 0 5 0 0
select top 1 1 from T4; 1 0 5 0 0
if exists(select 1 from t4) 1 0 5 0 0
(строк обработано: 5)
delete from T4;
(строк обработано: 10000)
select 1 where exists (select * from T4);
select top 1 1 from T4;
if exists(select 1 from t4) print 1;
-----------
(строк обработано: 0)
-----------
(строк обработано: 0)
object_name object_id used_page_count row_count
-------------------- ----------- -------------------- --------------------
T4 773577794 300 0
(строк обработано: 1)
sql_statement execution_count last_physical_reads last_logical_reads last_logical_writes last_elapsed_time
-------------------------------------------------- -------------------- -------------------- -------------------- -------------------- --------------------
select 1 where exists (select * from T4); 1 0 303 0 0
select top 1 1 from T4; 2 0 303 0 1001
if exists(select 1 from t4) 1 0 303 0 3001
delete from T4; 1 0 3048 129 121007
По сути, чтобы получить правильное значение количества строк в таблице, нужно выполнять запрос под уровнем изоляции SERIALIZABLE либо используя хинт TABLOCKXЭто смешно.
SELECT
o.[object_id]
, s.name + '.' + o.name
, o.[type]
, i.total_rows
, total_space = CAST(i.total_pages * 8. / 1024 AS DECIMAL(18,2))
, used_space = CAST(i.used_pages * 8. / 1024 AS DECIMAL(18,2))
, unused_space = CAST((i.total_pages - i.used_pages) * 8. / 1024 AS DECIMAL(18,2))
, index_space = CAST(i.inx_pages * 8. / 1024 AS DECIMAL(18,2))
, data_space = CAST(data_pages * 8. / 1024 AS DECIMAL(18,2))
, is_heap
, i.[partitions]
, i.[indexes]
FROM sys.objects o
JOIN sys.schemas s ON o.[schema_id] = s.[schema_id]
JOIN (
SELECT
i.[object_id]
, is_heap = MAX(CASE WHEN i.index_id = 0 THEN 1 ELSE 0 END)
, total_pages = SUM(a.total_pages)
, used_pages = SUM(a.used_pages)
, inx_pages = SUM(a.used_pages - CASE WHEN a.[type] !=1 THEN a.used_pages WHEN p.index_id IN(0,1) THEN a.data_pages ELSE 0 END)
, data_pages = SUM(CASE WHEN a.[type] != 1 THEN a.used_pages WHEN p.index_id IN (0,1) THEN a.data_pages END)
, total_rows = SUM(CASE WHEN i.index_id IN (0, 1) AND a.[type] = 1 THEN p.[rows] END)
, [partitions] = COUNT(DISTINCT p.partition_number)
, [indexes] = COUNT(DISTINCT p.index_id)
FROM sys.indexes i
JOIN sys.partitions p ON i.[object_id] = p.[object_id] AND i.index_id = p.index_id
JOIN sys.allocation_units a ON p.[partition_id] = a.container_id
WHERE i.is_disabled = 0
AND i.is_hypothetical = 0
GROUP BY i.[object_id]
) i ON o.[object_id] = i.[object_id]
WHERE o.[type] IN ('V', 'U')
AND o.is_ms_shipped = 0
ORDER BY i.total_pages DESC
У меня есть подборка простеньких вопросов, которые я люблю задавать при собеседовании. Например, как посчитать общее число записей к таблице? Вроде бы ничего сложного, но если копнуть глубже, то можно много интересных нюансов рассказать собеседнику.
SELECT COUNT(1), COUNT(*), COUNT(val), COUNT(DISTINCT val)
FROM (
VALUES (1), (1), (2), (NULL), (NULL)
) t (val)
Мне незнакомы конструкции когда в from стоит не имя таблицы, и не select-expression, но я и работать к вам идти не собираюсь.Тут из контекста понятно, даже есть не знать эту конструкцию.
Еще я знаю людей, которые любят использовать SUM вместо COUNT:
SELECT
E2WP.DepID
, [total] = SUM(1)
, [boss_male] = SUM(CASE WHEN ET.Code LIKE N'Boss' AND E2WP.Code LIKE N'M' THEN 1 ELSE 0 END)
, [boss_female] = SUM(CASE WHEN ET.Code LIKE N'Boss' AND E2WP.Code LIKE N'F' THEN 1 ELSE 0 END)
FROM dbo.tbl_Emp2WP E2WP
JOIN dbo.tbl_EmpType ET ON E2WP.EmpTypeID = ET.EmpTypeID
GROUP BY E2WP.DepID
COUNT(*)