Hesaplanan sütunlar ne zaman hesaplanır?


29

Hesaplanan sütunların değerleri ne zaman belirlenir?

  • Değer alındığında?
  • Değer ne zaman değiştirilir?
  • Başka zaman?

Aramalarımda hiçbir şey bulamadığım için bunun acemi bir soru olduğunu tahmin ediyorum.

Yanıtlar:


19

Hesaplanan sütunu nasıl tanımladığınıza bağlıdır. Bir PERSISTEDhesaplanan sütun hesaplanır ve daha sonra tablo içinde veri olarak saklanır. Sütunu olarak tanımlamazsanız, PERSISTEDsorgunuz çalıştırıldığında hesaplanır.

Lütfen harika bir açıklama ve kanıt için Aaron'un cevabına bakınız .

Pinal Dave ayrıca bunu ayrıntılı olarak açıklar ve dizisindeki depolama kanıtını gösterir:

SQL SERVER - Hesaplanan Sütun - PERSISTED ve Depolama


6
Peki ya bunlar ısrarsa, ama sorgu planı bu sütunu içermeyen bir indeks kullanıyorsa? Bir arama yapıp yapamayacağınıza ya da sadece anında hesaplayabildiğinden ve şu anda test edemediğinden emin değilim.
Martin Smith,

1
@Martin haklısın, testimde SQL Server bir arama üzerinden yeniden hesaplamayı seçti.
Aaron Bertrand

34

Bunu kendi başınıza kanıtlamak çok kolaydır. Skaler kullanıcı tanımlı bir işlev kullanan hesaplanmış bir sütuna sahip bir tablo oluşturabilir ve ardından bir güncelleme ve seçimden önce ve sonra planları ve işlev istatistiklerini kontrol edebilir ve bir uygulamanın ne zaman kaydedileceğini görebiliriz.

Diyelim ki bu işleve sahibiz:

CREATE FUNCTION dbo.mask(@x varchar(32))
RETURNS varchar(32) WITH SCHEMABINDING
AS
BEGIN
  RETURN (SELECT 'XX' + SUBSTRING(@x, 3, LEN(@x)-4) + 'XXXX');
END
GO

Ve bu masa:

CREATE TABLE dbo.Floobs
(
  FloobID int IDENTITY(1,1),
  Name varchar(32),
  MaskedName AS CONVERT(varchar(32), dbo.mask(Name)),
  CONSTRAINT pk_Floobs PRIMARY KEY(FloobID),
  CONSTRAINT ck_Name CHECK (LEN(Name)>=8)
);
GO

sys.dm_exec_function_statsEklemeden önce ve sonra ve sonra seçimden sonra (SQL Server 2016 ve Azure SQL Veritabanında yeni) kontrol edelim :

SELECT o.name, s.execution_count
FROM sys.dm_exec_function_stats AS s
INNER JOIN sys.objects AS o
ON o.[object_id] = s.[object_id]
WHERE s.database_id = DB_ID();

INSERT dbo.Floobs(Name) VALUES('FrankieC');

SELECT o.name, s.execution_count
FROM sys.dm_exec_function_stats AS s
INNER JOIN sys.objects AS o
ON o.[object_id] = s.[object_id]
WHERE s.database_id = DB_ID();

SELECT * FROM dbo.Floobs;

SELECT o.name, s.execution_count
FROM sys.dm_exec_function_stats AS s
INNER JOIN sys.objects AS o
ON o.[object_id] = s.[object_id]
WHERE s.database_id = DB_ID();

Eklemede sadece seçimde bir işlev çağrısı göremiyorum.

Şimdi, tabloları bırakın ve tekrar yapın, bu kez sütunu şu şekilde değiştirin PERSISTED:

DROP TABLE dbo.Floobs;
GO
DROP FUNCTION dbo.mask;
GO

...
  MaskedName AS CONVERT(varchar(32), dbo.mask(Name)) PERSISTED,
...

Ve bunun tam tersini görüyorum: Ekte kaydedilmiş bir yürütme alıyorum, ancak seçimde değil.

Kullanmak için yeterince modern bir SQL Server sürümünüz yok sys.dm_exec_function_statsmu? Endişeye gerek yok, bu da icra planlarında ele geçirildi .

Kalıcı olmayan sürüm için, yalnızca seçimde başvurulan işlevi görebiliriz:

görüntü tanımını buraya girin

görüntü tanımını buraya girin

Kalıcı sürüm yalnızca ekleme sırasında gerçekleşen hesaplamayı gösterirken:

görüntü tanımını buraya girin

görüntü tanımını buraya girin

Şimdi, Martin bir yorumda çok önemli bir nokta ortaya koyuyor : bu her zaman doğru olmayacak. Kalıcı hesaplanmış sütunu kapsamayan bir dizin oluşturalım ve bu dizini kullanan bir sorgu çalıştıralım ve aramanın varolan kalıcı verilerden veri alıp almadığını veya çalışma zamanında verileri hesapladığını görelim (bırak ve yeniden oluştur işlevi ve burada tablo):

CREATE INDEX x ON dbo.Floobs(Name);
GO

INSERT dbo.Floobs(name) 
  SELECT LEFT(name, 32) 
  FROM sys.all_columns 
  WHERE LEN(name) >= 8;

Şimdi, dizini kullanan bir sorgu çalıştıracağız (aslında bu durumda bu dizini varsayılan olarak kullanır, nerede olsa bile).

SELECT * FROM dbo.Floobs WITH (INDEX(x))
  WHERE Name LIKE 'S%';

İşlev istatistiklerinde ek işlemler görüyorum ve plan yalan söylemiyor:

görüntü tanımını buraya girin

Yani, cevap BT DEPENDS . Bu durumda, SQL Server, değerleri tekrar hesaplamanın arama yapmaktan daha ucuz olacağını düşünüyordu. Bu, çeşitli faktörlerden dolayı değişebilir, bu yüzden ona güvenmeyin. Ve bu, kullanıcı tanımlı bir fonksiyonun kullanılıp kullanılmadığı her iki yönde de olabilir; Ben sadece burada kullandım çünkü anlatılması çok daha kolaydı.


Çok takdir ediyorum, motorun hesaplama sonuçlarındaki davranışını asla sorgulamadım.
Arthur D

8
@ArthurD Her alternatifin tahmini maliyetine dayanan (çoğunlukla) bir optimize edici karardır, burada başka bir soruya cevabımı görün .
Paul White GoFundMonica

-1

Bu sorunun cevabı gerçekten "bağlıdır" dır. SQL Server'ın kalıcı hesaplanan sütunundaki dizini kullandığı bir örnekle karşılaştım ancak sanki değerler başlamaya asla devam etmediyse, hala işlevi yerine getiriyor. Sütunun ( nvarchar(37)) veri türüyle veya tablonun büyüklüğüyle (yaklaşık 7 milyon satır) ilgili olması gerekebilir , ancak SQL Serverpersisted bu özel örnekte anahtar kelimeyi .

Bu durumda, tablodaki birincil anahtar hesaplanan ve kalıcı bir sütun olan TransactionID'dir. Uygulama planı bir indeks taraması üretiyor ve sadece 7 milyon satırlık bir tabloda bu basit sorgu 2-3 dakika kadar sürüyor çünkü fonksiyon her satırda tekrar çalışıyor ve değerler kalıcı olarak görünmüyor İçerik.

kalıcı sütun içeren tablo oluşturma fonksiyon gösteren yürütme planı gerçekleştiriliyor

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.