MC, 13:38 piątek, 30.11.2012 r.
Ilustracja do artykułu: SQL Server (T-SQL) - Autokalkulowane kolumny, ich utrwalanie i łączenie z UDF

SQL Server (T-SQL) - Autokalkulowane kolumny, ich utrwalanie i łączenie z UDF

Gdy robimy autokalkulowaną kolumnę w tabeli, możemy zechcieć by była ona utrwalana w pamięci bazy danych. Podejście takie może jednak zrodzić problem, gdy zawartość tej kolumny determinowana jest przy pomocy UDF (User Definied Function). W tym wpisie chciałbym pokazać, jak pogodzić ze sobą te dwie możliwości.

Czym są kolumny automatycznie obliczane?

Odpowiedzi na to pytanie nie trudno się pewnie domyślić. Oczywiście chodzi o sytuację, w której wartość pewnej kolumny zostaje w sposób automatyczny wyznaczona, na podstawie wartości innych kolumn. Myślę, że najprostszym przykładem może być kolumna, która zwraca sumę wartości dwóch innych kolumn.
ALTER TABLE NaszSklep ADD LiczbaTowarow AS (LiczbaOwocow + LiczbaWarzyw)
Przykład jest trywialny. Dodajemy do tabeli NaszSklep nową kolumnę LiczbaTowarow, której wartość będzie sumą wartości z kolumn LiczbaOwocow oraz LiczbaWarzyw. Jak widzimy, nie podajemy typu danych przechowywanych w kolumnie - typ ten jest ustalany na podstawie wyrażenia definiującego zawartość kolumny.

O co chodzi z utrwalaniem danych z autokalkulowanej kolumny?

Bazując wciąż na przykładzie przedstawionym wyżej, z każdym razem wykonując kwerendę mającą na celu pobranie z tabeli wartości kolumny LiczbaTowarow, będzie ona wyliczana na nowo, a zatem nie będzie ona fizycznie utrwalona w pamięci bazy danych. Tak jednak być nie musi. Szukając optymalnej relacji pomiędzy rozmiarem bazy danych, a czasem wykonywania zapytań, możemy zechcieć, by wartość danej automatycznie wyliczanej kolumny, była utrwalana w sposób fizyczny. Wtedy nie będzie ona wyliczana na nowo podczas pobierania tych danych, a nastąpi to jedynie wtedy, gdy wprowadzimy zmiany do kolumn składowych (w naszym wypadku: LiczbaOwocow, LiczbaWarzyw). Chcąc tego dokonać, powinniśmy do wcześniejszej komendy, dołączyć dyrektywę PERSISTED:
ALTER TABLE NaszSklep ADD LiczbaTowarow AS (LiczbaOwocow + LiczbaWarzyw) PERSISTED
Bardzo istotny jest fakt, że aby kolumna mogła być utrwalona w pamięci bazy danych, składowe kolumny, muszą należeć do tej samej tabeli!

A co jeśli chcemy ustalać wartość kolumny przy pomocy UDF?

Nasz przykład jest bardzo prosty, dlatego mogliśmy sobie pozwolić na podanie formuły kalkulacji explicite już w komendzie dodającej daną kolumnę. Czasem jednak, w bardziej złożonych sytuacjach, wygodniej jest napisać funkcję, która pobierze odpowiednie wartości i zwróci pożądany rezultat. Jest to dobre rozwiązanie, gdy chcemy na przykład, by kilka kolumn ustalanych było przy pomocy tej samej procedury. Zakładając, że mamy funkcję sumujWartosci() przyjmującą dwa argumenty liczbowe i zwracającą ich sumę (na razie załóżmy, że już istnieje - zdefiniujemy ją w kolejnych akapitach), komenda dodająca automatycznie wyliczaną kolumnę, może wyglądać tak:
ALTER TABLE NaszSklep ADD LiczbaTowarow AS sumujWartosci(LiczbaOwocow, LiczbaWarzyw)
Oczywiście możemy sobie również zażyczyć, aby kolumna ta była utrwalana w pamięci (dopisujemy dyrektywę PERSISTED na końcu zapytania, tak jak miało to miejsce wcześniej), mając na względzie, wcześniejszą uwagę odnośnie tego, że funkcja musi operować jedynie w obrębie tej jednej tabeli.

Co jeśli operujemy na kolumnach jednaj tabeli, a jest problem z jej utrwaleniem?

Zdarzyć się może, że pomimo działania funkcji w obrębie jednej tabeli, nie będzie mogła być ona utrwalona, ponieważ jej wartość nie będzie mogła być ustalona, co zwieńczy komunikat błędu o treści:
Computed column 'LiczbaTowarow' in table 'NaszSklep' cannot be persisted because the column is non-deterministic.
W takiej sytuacji, należy upewnić się, czy zdefiniowana przez nas funkcja stworzona została z atrybutem SCHEMABINDING, co może wyglądać następująco:
CREATE FUNCTION dbo.sumujWartosci
(
@skladnik1 INT,
@skladnik2 INT
)
RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
RETURN @skladnik1 + @skladnik2
END

Czym jest SCHEMABINDING?

Jeśli jakiś obiekt wzbogacamy o atrybut SCHEMABINDING, informujemy tym samym, że obiekt ten jest powiązany ze wszystkimi swoimi odwołaniami, przez co nie możemy zmieniać ich struktury. Dlatego też dołączenie takiej informacji do funkcji powinno poskutkować możliwością utrwalenia wartości autokalkulowanej kolumny.

Komentarze (0) - Nikt jeszcze nie komentował - bądź pierwszy!

Imię:
Treść: