Persistent Computed Columns

Έχουν δημοσιευτεί 05 Φεβρουαρίου 07 07:40 μμ | KelMan 

Πολλές φορές χρειάζεται να σπάσουμε την κανονικοποίηση ενός πίνακα και να συμπεριλάβουμε computed columns. H θεωρία λέει ότι η τιμή κάθε computed column υπολογίζεται on-the-fly κάθε φορά που το χρησιμοποιεί κάποιο query και στη βάση δεν αποθηκεύεται τίποτα, έχουμε δηλαδή ένα virtual πεδίο. Όταν όμως η φόρμουλα του computed column είναι περίπλοκη (πχ μπορεί να περιέχει CASE) τότε ενδεχομένως να θέλαμε να αφαιρέσουμε λίγο φορτίο από τη CPU σε βάρος λίγου (ή πολύ) χώρου στο δίσκο ο οποίος θα μπορούσε να φιλοξενεί τις υπολογισμένες τιμές του πεδίου.

 

Mια τεχνική που χρησιμοποιούσαμε μέχρι σήμερα για να κάνουμε persist τις computed τιμές, ήταν να βάζουμε index πάνω στο computed πεδίο ώστε να έχουμε έτοιμες τις τιμές που θέλουμε να διαβάσουμε. Το πρόβλημα είναι ότι η συντήρηση του index έχει overhead γιατί το index δεν είναι και τόσο κατάλληλο γι αυτή τη δουλειά. Ένα UPDATE στα πεδία που απαρτίζουν το computed column ενδέχεται να έχει ως αποτέλεσμα πολύ περισσότερα write ops απ' όσα χρειάζονται για ένα αντίστοιχο απλό update ενός τυπικού πεδίου (όταν αυτό δεν έχει index), καθώς ενδεχομένως να χρειαστεί να γίνει και restructure του index.

 

Στον SQL Server 2005 υπάρχει η δυνατότητα να δηλώσουμε ένα computed column ως persistent πράγμα που σημαίνει ότι ο server θα διαχειρίζεται διαφανώς τις τιμές του computed πεδίου. Όταν τις διαβάζουμε, θα τις διαβάζουμε από τον δίσκο και όταν αλλάζουν τα πεδία που απαρτίζουν το computed column (στα Inserts και Updates) θα τo ενημερώνει αυτόματα. Ας δούμε ένα παράδειγμα:

 

Αρχικά, θα φτιάξουμε δύο πίνακες, έναν με persistent και ένα με μη-persistent computed column.

 

CREATE TABLE dbo.Product (

    ProductID INT,

    ProductName NVARCHAR(50),

    SellStartDate DATETIME NOT NULL,

    SellEndDate DATETIME NOT NULL,

    SellDuration AS DATEDIFF(dd, SellStartDate, SellEndDate) )

GO

 

CREATE TABLE dbo.ProductPCC (

    ProductID INT,

    ProductName NVARCHAR(50),

    SellStartDate DATETIME NOT NULL,

    SellEndDate DATETIME NOT NULL,

    SellDuration AS DATEDIFF(dd, SellStartDate, SellEndDate) PERSISTED )

GO

 

Το computed column είναι πολύ απλό, ίσα-ίσα για το proof-of-point. H μόνη διαφορά στους δύο πίνακες είναι το PERSISTED keyword στο πεδίο SellDuration. Κατόπιν θα γεμίζουμε τους δύο αυτούς πίνακες με δοκιμαστικά data.

 

DECLARE @i INT

DECLARE @SellStartDate DATETIME

DECLARE @SellEndDate DATETIME

SET @i = 1

WHILE @i < 1000

    BEGIN

        SET @SellStartDate = CAST(( 365.2422 * 105 ) * RAND() AS DATETIME)

        SET @SellEndDate = DATEADD(d, RAND() * 10000, @SellStartDate)

 

        INSERT  INTO Product

        VALUES  ( @i,

                  'test' + CAST(@i AS VARCHAR),

                  @SellStartDate,

                  @SellEndDate )

 

        INSERT  INTO ProductPCC

        VALUES  ( @i,

                  'test' + CAST(@i AS VARCHAR),

                  @SellStartDate,

                  @SellEndDate )

 

        SET @i = @i + 1

    END

GO

 

1000 εγγραφές με τυχαία SellStartDate και SellEndDate. Τώρα είμαστε έτοιμοι να δώσουμε τα query μας και να δούμε πως συμπεριφέρονται. Προσοχή! Επειδή μετά από κάθε SELECT θα χρησιμοποιούμε δύο Data Management Views για να μετρήσουμε την απόδοσή του, θα πρέπει να καθαρίζουμε την cache του Query Engine ώστε να έχουμε αξιόπιστα αποτελέσματα. Δίνουμε λοιπόν

 

DBCC DROPCLEANBUFFERS

DBCC FREEPROCCACHE

GO

 

Και τρέχουμε το πρώτο query. Αυτό δεν χρησιμοποιεί καθόλου computed columns και δουλεύει με την παραδοσιακή τεχνική.

 

SELECT  Product.ProductID,

        Product.ProductName,

        Product.SellStartDate,

        Product.SellEndDate,

        Product.SellDuration,

        DATEDIFF(dd, SellStartDate, SellEndDate) SellDuration

FROM    Product

 

Τώρα θα χρησιμοποιήσουμε τα δύο Data Management Views. Τα Data Management Views είναι κάποια system views που παρέχουν διάφορες πληροφορίες και είναι εξαιρετικά χρήσιμα. Αποτελούν το νέο τυποποιημένο τρόπο να κάνουμε διάφορες δουλίτσες, εκεί που χρησιμοποιούσαμε μέχρι σήμερα DBCCs, εξωτερικά εργαλεία, κλπ.

Το Sys.Dm_Exec_Query_Stats μας παρέχει στατιστικά για τα queries που έχουν εκτελεστεί. Είναι πολύ χρήσιμο καθώς μας γλυτώνει από την ανάγκη να χρησιμοποιήσουμε τον Profiler. Το sys.dm_exec_sql_text είναι βοηθητικό, για να πάρουμε το κείμενο του κάθε query. Τρέχουμε το παρακάτω λοιπόν:

 

SELECT  s2.text,

        total_worker_time,

        total_physical_reads,

        total_logical_reads,

        total_elapsed_time

FROM    Sys.Dm_Exec_Query_Stats

        CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS s2

 

και παίρνουμε

 

total_worker_time

total_physical_reads

total_logical_reads

total_elapsed_time

112742

3

9

126750

 

 

Ξανακάνουμε το ίδιο (μην ξεχάσετε τα DBCC), για το επόμενο query που χρησιμοποιεί το computed column:

 

GO

SELECT  Product.ProductID,

        Product.ProductName,

        Product.SellStartDate,

        Product.SellEndDate,

        Product.SellDuration

FROM    Product

GO

 

To query αυτό μας δίνει

 

total_worker_time

total_physical_reads

total_logical_reads

total_elapsed_time

73125

3

9

74515

 

 

Και τέλος, άλλη μια από τα ίδια για το persisted computed column

 

SELECT  ProductPCC.ProductID,

        ProductPCC.ProductName,

        ProductPCC.SellStartDate,

        ProductPCC.SellEndDate,

        ProductPCC.SellDuration

FROM    ProductPCC

GO

 

To DMV query μας δίνει τα παρακάτω αποτελέσματα:

 

total_worker_time

total_physical_reads

total_logical_reads

total_elapsed_time

58632

6

9

61130

 

 

Συγκεντρωτικά, έχουμε τα παρακάτω αποτελέσματα (τα δικά σας θα διαφέρουν):

 

 

total_worker_time

total_physical_reads

total_logical_reads

total_elapsed_time

Query 1

112742

3

9

126750

Query 2

73125

3

9

74515

Query 3

58632

6

9

61130

 

Γενικά, φαίνεται ότι τα persistent computed columns έχουν πολύ καλύτερο performance, φυσικά με trade-off τον αποθηκευτικό χώρο.

 

Μπορείτε να συνεχίσετε τα πειράματα. Δοκιμάστε να βάλετε ένα index πάνω στο computed πεδίο και στους δύο πίνακες για να δείτε πως θα επηρεαστούν τα αποτελέσματα. Επιπρόσθετα, πριν αποφασίσετε να τα χρησιμοποιήσετε, θα πρέπει να εξετάσετε τι γίνεται με τα write ops από πλευράς performance. Γενικά, τα write ops δημιουργούν overhead οπότε ένας πίνακας με πολλά write ops ενδέχεται να μην είναι κατάλληλος για persistent computed columns.

 

Δημοσίευση στην κατηγορία: , ,

Σχόλια:

Χωρίς Σχόλια
Έχει απενεργοποιηθεί η προσθήκη σχολίων από ανώνυμα μέλη

Search

Go

Συνδρομές