Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

SQL Server избира произволна (или първа) стойност с агрегиране

Има недокументиран агрегат наречено ANY което не е валиден синтаксис, но е възможно да се появи във вашите планове за изпълнение. Това обаче не осигурява никакво предимство в производителността.

Приемаме следната структура на таблица и индекс

CREATE TABLE T
(
id int identity primary key,
[group] char(1) 
)

CREATE NONCLUSTERED INDEX ix ON T([group])

INSERT INTO T
SELECT TOP 1000000 CHAR( 65 + ROW_NUMBER() OVER (ORDER BY @@SPID) % 3)
FROM sys.all_objects o1, sys.all_objects o2, sys.all_objects o3

Също така попълних с примерни данни, така че да има много редове на група.

Вашата оригинална заявка

SELECT MAX(id),
       [group]
FROM   T
GROUP  BY [group]  

Дава Table 'T'. Scan count 1, logical reads 1367 и плана

  |--Stream Aggregate(GROUP BY:([[T].[group]) DEFINE:([Expr1003]=MAX([[T].[id])))
       |--Index Scan(OBJECT:([[T].[ix]), ORDERED FORWARD)

Пренаписан, за да получите ANY съвкупност...

;WITH cte AS
(
SELECT *,
        ROW_NUMBER() OVER (PARTITION BY [group] ORDER BY [group] ) AS RN
FROM T)
SELECT id,
       [group]
FROM    cte     
WHERE RN=1

Дава Table 'T'. Scan count 1, logical reads 1367 и плана

  |--Stream Aggregate(GROUP BY:([[T].[group]) DEFINE:([[T].[id]=ANY([[T].[id])))
       |--Index Scan(OBJECT:([[T].[ix]), ORDERED FORWARD)

Въпреки че потенциално SQL Server може да спре обработката на групата веднага щом бъде намерена първата стойност и да премине към следващата, той не го прави. Все още обработва всички редове и логическите четения са същите.

За този конкретен пример с много редове в групата по-ефективна версия би била рекурсивен CTE.

WITH    RecursiveCTE
AS      (
        SELECT TOP 1 id, [group]
        FROM T
        ORDER BY [group]
        UNION   ALL
        SELECT  R.id, R.[group]
        FROM    (
                SELECT  T.*,
                        rn = ROW_NUMBER() OVER (ORDER BY (SELECT 0))
                FROM    T
                JOIN    RecursiveCTE R
                        ON  R.[group] < T.[group]
                ) R
        WHERE   R.rn = 1
        )
SELECT  *
FROM    RecursiveCTE
OPTION  (MAXRECURSION 0);

Което дава

Table 'Worktable'. Scan count 2, logical reads 19
Table 'T'. Scan count 4, logical reads 12

Логическите четения са много по-малко, тъй като извлича първия ред на група, след което търси в следващата група, вместо да чете множество записи, които не допринасят за крайния резултат.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Актуализиране на записи на SQL Server 2008 с типове пространствени данни чрез Massive ORM (ExecuteNonQuery), грешка UdtTypeName

  2. Неправилен синтаксис близо до „GO“

  3. Стандартни низове за формат на дата/час, поддържани от FORMAT() в SQL Server

  4. МЕЖДУ оператор срещу>=И <=:Има ли разлика в производителността?

  5. Как да разберете към коя таблица принадлежи заключване на страница