Jump to content

antonch

Administrators
  • Posts

    1030
  • Joined

  • Last visited

  • Days Won

    7

Blog Entries posted by antonch

  1. antonch
    Δεν ξέρω αν είχατε την δυνατότητα να δείτε τα δύο poster που έχω φτίαξει για τις δυνατότητες του SQL Server 2008 R2.

    Φτιάχνοντας τα εντόπιζα πράγματα τα οποία με εντυπωσίαζαν. Αυτά που μου έκαναν περισσότερη εντύπωση ήταν δύο.

    1. Το πόσους SQL Servers μπορώ να διαχειριστώ σε multi-instance management;

    Η απάντηση είναι 250 στην Datacenter edition και 25 στην Enterprise.

    2. To πόσους indexes μπορώ να έχω σε ένα πίνακα;

    Μέχρι την έλευση του SQL Server 2008 R2 είχα την δυνατότητα να έχω 250 indexes σε κάθε πίνακα (1 clustered + 249 nonclustered). Στο SQL Server 2008 R2 σε όλες τις εκδόσεις έχω 1000 indexes!!!!! (1 clustred + 999 nonclustred). Είμαι περίεργος να δω ποιος θα βάλει τόσους indexes σε ένα πίνακα.

     
  2. antonch
    Το πρόβλημα

    Πριν από μερικές μέρες μια συνάδελφος ήρθε με το εξής πρόβλημα, ήθελε να δείξει κάποια δεδομένα σε ένα treeview control σε ένα web page. Στην ουσία ήταν μια ιεραρχία που από την δομή του πίνακα έβγαινε αρκετά εύκολα με ένα order by clause. Όμως δεν ήταν τόσο απλά τα πράγματα, ήθελε να υπάρχει ταξινόμηση ανά επίπεδο ιεραρχίας το οποίο ορίζονταν από ένα άλλο πεδίο.

    Για να εξηγήσουμε καλύτερα την πρόκληση αυτή ας έρθουμε να δούμε το πώς ήταν τα δεδομένα της

    Ολόκληρο το άρθρο θα το βρείτε εδώ καθώς χρειάστηκε να το αναθεωρήσω
  3. antonch
    Πριν από λίγο ήμουν με ένα φίλο και συνάδελφο και κάναμε διάφορα πραγματάκια σε μία βάση. Κάποια στιγμή θέλαμε να αλλάξουμε την τιμή από ένα πεδίο σε ένα record σε null και βαριόμουν να κάτσω να γράψω ένα update statement. Έτσι άνοιξα τον SSMS και με την γνωστή διαδικασία δεξι κλικ Edit πάνω στο πίνακα που θέλω στην βάση μου πήγα στο πεδίο και πάτησα Ctrl+0 όπου αμέσα γίνεται null η τιμή του και το μόνο που έχεις να κάνει είναι να πας στην επόμενη εγγραφή για να γινει commit η αλλαγή σου. Η κίνηση αυτή ξάφνιασε τον φίλο και συνάδελφο μιας και είναι από τους δυνατούς παίχτες έτσι σκέφτηκα να τα μοιραστώ με περισσότερους που ίσως δεν το γνώριζαν.
  4. antonch
    Σαν developers αρκετές φορές ερχόμαστε αντιμέτωποι με προβλήματα που πρέπει να λύσουμε μέσα σε σύντομο χρονικό διάστημα. Τις περισσότερες φορές η λύση που επιλέγουμε για να το λύσουμε είναι αυτή που ξέρουμε καλύτερα, την έχουν χρησιμοποιήσει αρκετές φορές, την εμπιστευόμαστε περισσότερο ή αυτή ξέρουμε μόνο.
    Κάποιες φορές αυτή είναι ιδανική, καλή, μέτρια ή άστα να πάνε…
    Ας έρθουμε όμως στο προκείμενο…
    Πριν μερικές μέρες είχα να αντιμετωπίσω ένα θέμα το οποίο πάντα όταν ανακύπτει προκαλεί πολλά σχόλια, αρνητικά κυρίως, από συναδέλφους που βλέπουν το SQL Server σαν ένα μέσω αποθήκευσης και μόνο των δεδομένων, αυτό που εγώ λέω κουβά.
    Το πρόβλημα είναι το εξής «Έχω ένα ή περισσότερους πίνακες που θέλω να τους ρωτήσω με πολλαπλά φίλτρα τα οποία άλλες φορές θα έχουν τιμή και άλλες όχι. Με ποιο απλά λόγια αν το φίλτρο έχει τιμή τότε θέλω να είναι στο WHERE αλλιώς όχι».
    Αυτό όταν το ακούς ή το αντιμετωπίζεις, άμεσα το μυαλό σου πηγαίνει στο «θέλω δυναμικά να κτίζω το WHERE clause στο SELECT που θα κάνω».
    Αυτό σημαίνει αρκετά πράγματα τα οποία θα ήταν κουτό από μέρος μου να κάτσω να τα γράψω μιας και ο Erland Sommarskog (blog), MVP και αυτός στον SQL Server, έχει ήδη γράψει ένα καταπληκτικό post με τίτλο «The Curse and Blessings of Dynamic SQL», το οποίο και εγώ πριν αρχίσω την συγγραφή αυτού του post δεν γνώριζα την ύπαρξη του. Αλλά ευτυχώς είχα την προνοητικότητα να ρωτήσω τους άλλους MVPs αν κάποιος έχει γράψει κάτι για αυτό ώστε να εστιάσω την προσοχή μου σε αυτό που θέλω να αναλύσω χωρίς να γράψω όλη την ιστορία από την αρχή.Thanks Er!.
    Ας πάρουμε για παράδειγμα το εξής:
    Θέλω να έχω μια stored procedure που να παίρνει σαν παραμέτρους πεδία του πίνακα Customers και του πίνακα Orders από την Northwind και ανάλογα να κάνει αναζήτηση με το τι τιμές ή όχι έχω δώσει σε αυτές και να μου επιστρέφει το επιθυμητό αποτέλεσμα που στην περίπτωση του παραδείγματος μας θα είναι οι παραγγελίες ανά πελάτη.
    Αυτό σημαίνει ότι η συγκεκριμένη stored pocedure θα πρέπει να έχει την δυνατότητα να μην πάρει τιμές σε καμία από αυτές άρα θα πρέπει αυτές να είναι αρχικοποιημένες με μια τιμή που στην περίπτωση μας η τιμή αυτή θα είναι null. Έτσι ένα πιθανό stored procedure signature θα μπορούσε να είναι το παρακάτω
    CREATE PROC spGetCustomerOrders
    @CompanyName NVARCHAR(40)=NULL,
    @Country NVARCHAR(15)=NULL,
    @City NVARCHAR(15)=NULL,
    @Region NVARCHAR(15)=NULL,
    @OrderDate_Min DATETIME=NULL,
    @OrderDate_Max DATETIME=NULL,
    @Employees NVARCHAR(100)=NULL




    Το αποτέλεσμα που θέλω να επιστρέφει είναι το εξής query


    SELECT o.OrderID,
    o.EmployeeID,
    c.CustomerID,
    c.CompanyName,
    o.OrderDate,
    c.Country,
    c.City,
    c.Region
    FROM Customers c
    INNER JOIN Orders o ON c.CustomerID=o.CustomerID

    το οποίο θέλω να έχει τα εξής φίλτρα κατά την αναζήτηση φυσικά όταν για αυτά μου έχουν δώσει τιμές αλλιώς δεν θέλω να μπλέκονται σε αυτή. Σε πλήρη ανάπτυξη τα φίλτρα μου θέλω να είναι όπως παρακάτω


    WHERE
    c.CompanyName LIKE @CompanyName + '%'
    AND
    c.Country = @Country
    AND
    c.City = @City
    AND
    c.Region = @Region
    AND
    o.OrderDate BETWEEN @OrderDate_Min AND @OrderDate_Max
    AND
    o.EmployeeID IN ()

    Αν σαν πρώτη σκέψη είχα το dynamic sql τότε μια πιθανή υλοποίηση θα ήταν η παρακάτω


    CREATE PROC spGetCustomerOrders @CompanyName NVARCHAR(40)=NULL,
    @Country NVARCHAR(15)=NULL,
    @City NVARCHAR(15)=NULL,
    @Region NVARCHAR(15)=NULL,
    @OrderDate_Min DATETIME=NULL,
    @OrderDate_Max DATETIME=NULL,
    @Employees NVARCHAR(100)=null
    AS

    SET NOCOUNT ON;

    DECLARE @select nvarchar(2000)
    DECLARE @where nvarchar(1000)

    SET @OrderDate_Min = ISNULL(@OrderDate_Min,'19000101')
    SET @OrderDate_Max = ISNULL(@OrderDate_Max,'99991231')

    IF ( @OrderDate_Min > @OrderDate_Max )
    BEGIN
    RAISERROR ('@OrderDate_Min is bigger than @OrderDate_Max',16,1)
    RETURN
    END

    SET @select = 'SELECT o.OrderID, o.EmployeeID, c.CustomerID, c.CompanyName, o.OrderDate, c.Country, c.City, c.Region FROM Customers c INNER JOIN Orders o ON c.CustomerID=o.CustomerID '

    -- ΓΙΑ ΝΑ ΕΙΜΑΙ ΑΣΦΑΛΕΙΣ ΕΔΩ ΘΑ ΠΡΈΠΕΙ ΝΑ ΕΛΕΞΩ ΓΙΑ SQL INJECTION

    SET @where = 'WHERE (o.OrderDate BETWEEN ''' + CONVERT(char(10),@OrderDate_Min,102) + ''' AND ''' + CONVERT(char(10),@OrderDate_Max,102) + ''')'
    if not @CompanyName is null SET @where += ' AND (c.CompanyName LIKE ''' + @CompanyName + '%' +''')'
    if not @Country is null SET @where += ' AND (c.Country = ''' + @Country + ''')'
    if not @City is null SET @where += ' AND (c.City = ''' + @City + ''')'
    if not @Region is null SET @where += ' AND (c.Region = ''' + @Region + ''')'
    if not @Employees is null SET @where += ' AND (o.EmployeeID IN ('+ @Employees + '))'
    SET @select += @where
    EXEC (@select)
    GO

    Και ο τρόπος εκτέλεσης της θα ήταν ο παρακάτω


    exec spGetCustomerOrders @CompanyName = 'c',
    @Country ='UK',
    @City =null,
    @Region =null,
    @OrderDate_Min =null,
    @OrderDate_Max =null,
    @Employees ='1,2,3,4'

    Ουφ κουράστηκα να γράφω και να προσέχω τα μονά quotes που ανοίγουν που κλείνουν να βάζω ακόμα ένα σε αυτά ώστε να συμπεριληφθούν στο string, α και να προσέξω για sql injection.


    Το τελευταίο θα μπορούσα εύκολα να το αποφύγω αν άλλαζα τον κτίσιμο του sql statement όπως παρακάτω


    CREATE PROC spGetCustomerOrders @CompanyName NVARCHAR(40)=NULL,
    @Country NVARCHAR(15)=NULL,
    @City NVARCHAR(15)=NULL,
    @Region NVARCHAR(15)=NULL,
    @OrderDate_Min DATETIME=NULL,
    @OrderDate_Max DATETIME=NULL,
    @Employees NVARCHAR(100)=null
    AS

    SET NOCOUNT ON;

    DECLARE @select nvarchar(2000)
    DECLARE @where nvarchar(1000)

    SET @OrderDate_Min = ISNULL(@OrderDate_Min,'19000101')
    SET @OrderDate_Max = ISNULL(@OrderDate_Max,'99991231')

    IF ( @OrderDate_Min > @OrderDate_Max )
    BEGIN
    RAISERROR ('@OrderDate_Min is bigger than @OrderDate_Max',16,1)
    RETURN
    END

    SET @select = 'SELECT o.OrderID, o.EmployeeID, c.CustomerID, c.CompanyName, o.OrderDate, c.Country, c.City, c.Region FROM Customers c INNER JOIN Orders o ON c.CustomerID=o.CustomerID '
    SET @where = 'WHERE (o.OrderDate BETWEEN @OrderDate_Min AND @OrderDate_Max)'

    if not @CompanyName is null SET @where += ' AND (c.CompanyName LIKE @CompanyName)'
    if not @Country is null SET @where += ' AND (c.Country = @Country)'
    if not @City is null SET @where += ' AND (c.City = @City )'
    if not @Region is null SET @where += ' AND (c.Region = @Region )'
    if not @Employees is null SET @where += ' AND (o.EmployeeID IN (@Employees))'
    SET @select += @where

    EXEC sp_executesql @select,N'@CompanyName NVARCHAR(40), @Country NVARCHAR(15), @City NVARCHAR(15), @Region NVARCHAR(15), @OrderDate_Min DATETIME, @OrderDate_Max DATETIME, @Employees NVARCHAR(100)', @CompanyName, @Country, @City, @Region, @OrderDate_Min, @OrderDate_Max, @Employees

    GO

    Και ο τρόπος εκτέλεσης της θα ήταν ο παρακάτω


    exec spGetCustomerOrders @CompanyName = 'c%',
    @Country ='UK',
    @City =null,
    @Region =null,
    @OrderDate_Min =null,
    @OrderDate_Max =null,
    @Employees =null

    Μήπως όμως θα μπορούσα να την γράψω αλλιώς; Χωρίς dynamic sql; Ας το δοκιμάσουμε.


    Αρχικά με ενοχλεί η παράμετρος @Employees που είναι nvarchar. Θα ήθελα να είναι array. Μα καλά θα μου πεις array σε T-SQL, τι πίνεις;


    Όντως η έννοια αυτή δεν υπάρχει σε T-SQL, όμως υπάρχουν οι πίνακες και τα table-value parameters. Έτσι φτιάχνω ένα δικό μου data type που θα είναι table data type και θα παίζει το ρόλο του array


    CREATE TYPE OrderEmployees AS TABLE (EmployeeID INT);
    GO

    Και θα αλλάξω την παράμετρο @Employees σε αυτό το table data type. Έτσι πλέον το stored procedure signature θα γίνει


    CREATE PROC spGetCustomerOrders @CompanyName NVARCHAR(40)=NULL,
    @Country NVARCHAR(15)=NULL,
    @City NVARCHAR(15)=NULL,
    @Region NVARCHAR(15)=NULL,
    @OrderDate_Min DATETIME=NULL,
    @OrderDate_Max DATETIME=NULL,
    @Employees OrderEmployees READONLY

    Για να ξέρω αν έχω rows στο @Employees table-value parameter δηλώνω την μεταβλητή @ HasEmployees σαν bit (Boolean) και την γεμίζω ανάλογα 0 δεν έχω, 1 έχω rows


    DECLARE @HasEmployees BIT
    SET @HasEmployees = CASE WHEN (SELECT COUNT(*) FROM @Employees)>0 THEN 1 ELSE 0 END

    Αρχικοποιώ και τις @OrderDate_Min, @OrderDate_Max ώστε να μπορώ να παίρνω όλα τα rows σε περίπτωση που δεν μου δώσουν τιμές


    SET @OrderDate_Min = ISNULL(@OrderDate_Min,'19000101')
    SET @OrderDate_Max = ISNULL(@OrderDate_Max,'99991231')




    Η υλοποίηση της θα μπορούσε να είναι η παρακάτω


    CREATE PROC spGetCustomerOrders @CompanyName NVARCHAR(40)=NULL,
    @Country NVARCHAR(15)=NULL,
    @City NVARCHAR(15)=NULL,
    @Region NVARCHAR(15)=NULL,
    @OrderDate_Min DATETIME=NULL,
    @OrderDate_Max DATETIME=NULL,
    @Employees OrderEmployees READONLY
    AS

    SET NOCOUNT ON;

    DECLARE @HasEmployees BIT
    SET @OrderDate_Min = ISNULL(@OrderDate_Min,'19000101')
    SET @OrderDate_Max = ISNULL(@OrderDate_Max,'99991231')
    SET @HasEmployees = CASE WHEN (SELECT COUNT(*) FROM @Employees)>0 THEN 1 ELSE 0 END

    SELECT o.OrderID, o.EmployeeID, c.CustomerID,c.CompanyName,o.OrderDate,c.Country,c.City,c.Region
    FROM Customers c
    INNER JOIN Orders o ON c.CustomerID=o.CustomerID
    WHERE
    ((c.CompanyName LIKE @CompanyName + '%') OR (@CompanyName IS NULL))
    AND
    ((c.Country = @Country) OR (@Country IS NULL))
    AND
    ((c.City = @City) OR (@City IS NULL))
    AND
    ((c.Region = @Region) OR (@Region IS NULL))
    AND
    (o.OrderDate BETWEEN @OrderDate_Min AND @OrderDate_Max )
    AND
    (CASE @HasEmployees
    WHEN 0 THEN 1
    ELSE
    CASE WHEN o.EmployeeID IN (SELECT EmployeeID FROM @Employees) THEN 1
    ELSE 0
    END
    END = 1 )
    GO

    Και η εκτέλεση αυτής


    DECLARE @e OrderEmployees
    -- Κάνω remark το insert αυτό αν θέλω να προσομοιάσω το γεγονός ότι δεν μου δίνουν τιμές στους υπαλλήλους
    INSERT INTO @e VALUES (8),(4)

    EXEC spGetCustomerOrders @CompanyName='c',
    @Country='UK',
    @City=NULL,
    @Region=NULL,
    @OrderDate_Min=NULL,
    @OrderDate_Max=NULL,
    @Employees=@e

    Το σημαντικό όμως είναι η διαφορά σε χρόνο εκτέλεσης καθώς η λύση που δεν περιέχει το dynamic sql είναι γρηγορότερη τουλάχιστον κατά 60%
  5. antonch
    Today I’m pleased to announce the availability of the SQL Server 2008 R2 Update For Developers January 2011 Update. This is a great resource for developers, trainers, consultants and evangelists who need to understand the key improvements introduced in SQL Server 2008 and SQL Server 2008 R2 from a developer perspective. It contains a rich set of presentations, demos, hands-on labs and videos that are perfect for self-paced learning or for conducting your own training. The January 2011 update includes lots of great new content and several usability improvements.
    The easiest way to get started with the training kit is to download it, install it, open default.htm and browse the kit for the content that you are most interested in. Many of the presentations and demos in the training kit include a video that you can watch to familiarize yourself with the content. When you are ready for some hands-on experience, try installing one of the demos or hands-on labs. Each of them includes a configuration wizard that simplifies installation. Check out the following sections for more on what’s new in this update.
    Ø New Content: Build Your First Microsoft BI Solution with SQL Server 2008 R2
    Ø Other Content in the Training Kit
    Ø Usability Improvements
    Ø Virtual Machine Information
    Ø What’s Next
    You can download the training kit now at the following URL:
    http://go.microsoft.com/?linkid=9710868
    This training kit is brought to you by DPE’s Data Platform Evangelism team. Please feel free to email us at [email protected] with your feedback and questions. We are particularly interested in hearing about use of this content to drive SQL Server developer adoption.
    Regards,
    Roger
    Roger Doherty | Sr. Technical Evangelist | Microsoft Corp.
  6. antonch
    Σε συνέχεια από το PART I.
    Report Server Databases
    Στα SSRS έχουμε δύο databases τις ReportServer και ReportServerTempDB.
    ReportServer Database
    Σε αυτή την βάση αποθηκεύονται τα παρακάτω
    SSRS configuration Report definitions Report metadata Report history Cache policies Snapshots Resources Security settings Encrypted data Scheduling and Delivery Data Extension information Όπως είναι εύκολα κατανοητό η βάση αυτή είναι και η καρδία των SSRS και φυσικά η απώλεια της σημαίνει πολλά. Για αυτό το λόγο και της συμπεριφερόμαστε όπως σε όλες τις βάσεις παραγωγής, πχ παίρνουμε καθημερινό backup.
    Επίσης θα πρέπει να τονίσω ότι μπορώ να έχω άμεση πρόσβαση στα δεδομένα των πινάκων και φυσικά να αλλοιώσω αυτά. Αυτό όμως δεν είναι recommended αλλά ούτε και supported από την Microsoft. Επίσης θα πρέπει να τονισθεί ότι υπάρχει πάντα το ενδεχόμενο με κάποιο CU ή SP η δομή της βάσης να αλλάξει.
    ReportServerTempDB Database
    Αυτή η βάση είναι υπεύθυνη για την αποθήκευση των ενδιάμεσων διαδικασιών όπως των cached reports , sessions και execution data.
    Σε αντίθεση με την TempDB του SQL Server τα δεδομένα σε αυτή την βάση παραμένουν όταν γίνεται restart είτε ο SQL Server είτε τα SSRS. Σε τακτά χρονικά διαστήματα γίνεται διαγραφή των expired και orphan data.
    Αν και μπορούμε να σβήσουμε όλα τα δεδομένα μέσα από αυτή καλό είναι να γίνει αυτό. Αν και το μόνο που μπορεί να μας συμβεί είναι οι χρήστε που είναι σε διαδικασία να δούνε ένα report θα πάρουν μήνυμα ότι δεν μπορούν να διαβάσουν τον session state (rsExecutionNotFound). Σε αυτή την περίπτωση ο χρήστης θα πρέπει να ξαναεκτελέσει το report.
    Αλλαγή θέσης των Temporary Snapshots
    Εάν κάποιος θέλει να αλλάξει τον τρόπο που temporary snapshots αποθηκεύονται και αντί για την βάση να αποθηκεύονται σε directory θα πρέπει να ακολουθήσει τα επόμενα βήματα
    Να αλλάξει στο rsreportserver.config το WebServiceUseFileShareStorage και το WindowsServiceUseFileShareStorage σε True. Να ορίζει το path που θέλει αυτά να αποθηκεύονται στο FileShareStorageLocation. Υπάρχει βέβαια default value και είναι η C:\Program Files\Microsoft SQL Server\MSES10.MSSQLSERVER\Reporting Services\RSTempFiles. Τέλος θα πρέπει να επισημάνω ότι δεν χρειάζεται οι βάσεις αυτές να είναι στην ίδια μηχανή που έχω στήσει τα SSRS αλλά σε έναν άλλο SQL Server.
  7. antonch
    Είχα σκοπό να τα φτιάξω κάτι σχετικό, αλλά ψάχνοντας για κάτι άλλο, έπεσα επάνω τους. Σας δίνω τα links ώστε να τα δείτε.
    Installation of a Single Node Failover Cluster in SQL Server 2008
    Add a Node to an Existing Failover Cluster in SQL Server 2008
    Remove a Passive Node from an Existing Failover Cluster in SQL Server 2008
    Remove the Active Node from an Existing Failover Cluster in SQL Server 2008
  8. antonch
    Τις τελευταίες ημέρες είχα την ευτυχία να ανακαλύψω μερικά ωραία ασχολούμενος με μια βάση
    1. Δήλωση πεδίου σε πίνακα σαν varchar(1) not null
    2. Δήλωση πεδίου σε πίνακα που κρατάει το τηλέφωνο σαν varchar(max) not null (μεγάλε που θα πάρεις τηλέφωνο?)
  9. antonch
    Με αφορμή το τελευταίο μου SQL Server Saturday Night που σαν θέμα είχε τον SQL Server Profiler και μπορείτε να το δείτε εδώ και στο οποίο αναφέρθηκα στο συγκεκριμένο θέμα αποφάσισα να γράψω το συγκεκριμένο ώστε να δώσω περισσότερες λεπτομέρειες.
    Όπως ανέφερα και στη παρουσίαση μου το ποια events θα διαλέξει κάνεις έχει περισσότερο να κάνει με την εμπειρία που έχει αλλά και την ικανότητα με αυτά να εντοπίσει το εν λόγω πρόβλημα.
    Προσωπικά επιλέγω αυτά που θα σας παραθέσω παρακάτω αλλά αυτό φυσικά δεν είναι το απόλυτο. Ο καθένας από εσάς μπορεί να προσθέσει ή να αφαιρέσει events με τα οποία πιστεύει ότι θα κάνει καλύτερα την αναζήτηση του στο θέμα μας.
    Για να διαβάσετε την συνέχεια του άρθρου κάνετε click εδώ
    Enjoy it!
    antonch
  10. antonch
    Όταν δημιουργήτε ένα report το οποίο έχει μέσα του images και θέλετε να έχετε μικρό μέγεθος αρχείου όταν το κάνετε export σε PDF, φροντίστε αυτές να είναι σε jpeg format.
    Οτιδήποτε άλλο τα reporting services το μεταφράζουν σε BMP και αυτό έχει σαν αποτέλεσμα να μεγαλώνει δραματικά το μέγεθος του αρχείο ειδικότερα αν έχετε μεγάλο αριθμό από εικόνες ή φωτογραφίες.
  11. antonch
    Αφορμή για το post αυτό μου έδωσε αυτό το post, Protect object from accidental deletion.
    Για να κάνω κάτι τέτοιο στον SQL Server το μόνο που χρειάζεται να κάνω είναι να φτιάξω ένα απλό DML Trigger.
    Με το παρακάτω script γίνεται αυτό που θέλω και έτσι δεν πρόκειτε ποτέ να σβήσω μια βάση. Αν θελήσω να σβήσω μια βάση θα πρέπει πρώτα να κάνω disable τον trigger να κάνω την διαγραφή μου και μετά να ενεργοποίησω ξανά αυτόν.
    CREATE TRIGGER NoDeleteDB ON ALL SERVER FOR DROP_DATABASE
    AS
    ROLLBACK
    GO
    DISABLE TRIGGER NoDeleteDB ON ALL SERVER
    ENABLE TRIGGER NoDeleteDB ON ALL SERVER
  12. antonch
    Γνωρίζοντας ότι μπορεί το παρόν post μου να μην είναι ενδιαφέρον ή να προσφέρει μια γνώση που δεν έχετε, εντούτοις το γράφω διότι πρέπει κάποια πράγματα να λέγονται όπως είναι και να μην υπάρχει μαύρες τρύπες ή διαφορετικές ερμηνείες, που δυστυχώς άκουσα σήμερα.

    Τι είναι λοιπόν ένα transaction;

    Είστε σε μια εκκλησία και βλέπετε ένα ζευγάρι να παντρεύεται. Όταν τελειώσει το μυστήριο του γάμου δεν υπάρχει κανένας που να αμφιβάλλει για το status του ζευγαριού αυτού. ΕΙΝΑΙ ΠΑΝΤΡΕΜΕΝΟΙ. Εάν όμως κατά την διάρκεια του μυστήριου συμβεί κάτι πχ η νύφη το σκάσει πάλι δεν υπάρχει καμία αμφιβολία για το status τους. ΔΕΝ ΕΙΝΑΙ ΠΑΝΤΡΕΜΕΝΟΙ.

    Αυτό στην ουσία είναι και ένα transaction αγαπητές κυρίες και αγαπητοί κύριοι. Τίποτα περισσότερο τίποτα λιγότερο. Οι σύμμαχοι λένε All Or Nothing, που σημαίνει ότι όλα θα γίνουν και θα φτάσω στο επιθυμητό status (ΕΙΝΑΙ ΠΑΝΤΡΕΜΕΝΟΙ-TRANSACTION IS COMMITTED) ή αν γίνει κάτι τότε όλα γυρνάνε στην προηγούμενη κατάσταση (ΔΕΝ ΕΙΝΑΙ ΠΑΝΤΡΕΜΕΝΟΙ – TRANSACTION ROLLBACKED)

    Ένα transaction υλοποίει – διέπεται από τα ACID properties που είναι τα αρχικό των λέξεων Atomicity – Consistency – Isolation – Durability.

    Atomicity σημαίνει ότι κάθε transaction πρέπει να είναι μια αυτόνομη εργασία που είτε θα γίνουν όλα όσα αυτή ζητάει να γίνουν είτε δεν θα γίνει τίποτα.

    Consistency σημαίνει ότι με την ολοκλήρωση του transaction όλα θα είναι σε μια consistent κατάσταση (είναι παντρεμένοι ή δεν είναι παντρεμένοι). Ενδιάμεσες καταστάσεις δεν υπάρχουν. Δεν υπάρχει ολίγο παντρεμένοι ή ολίγο δεν είναι παντρεμένοι.

    Isolation σημαίνει ότι οι αλλαγές που ζητάει ένα transaction να γίνουν πρέπει να είναι απομονωμένες από τις αλλαγές που κάποια άλλα transaction που εκτελούνται ταυτόχρονα κάνουν. Δηλαδή εάν για παράδειγμα κάποιος από το ζευγάρι που παντρεύεται είναι ήδη παντρεμένο το δικό μας transaction δεν θα προχωρήσει. Ξέρω τι θα ακούσω τώρα για τα ζευγάρια που είναι δίγαμα αλλά αυτό διώκεται ποινικά ξέρετε, έτσι και εδώ υπάρχουν νόμοι και κανόνες που ευτυχώς δεν παραβιάζονται. Επίσης για να προχωρήσει το δικό μας transaction όταν κάποιο ή κάποια άλλα έχουν ξεκινήσει θα πρέπει αυτά να τελειώσουν και να αφήσουν τα δεδομένα που και εμείς θέλουμε να πειράξουμε σε μια ξεκάθαρη κατάσταση.

    Durability σημαίνει ότι αφού το transaction μας έχει ολοκληρωθεί αυτό παραμένει ακόμα και αν το σύστημα μας έχει failure.

    Για να επιτευχθούν όλα τα παραπάνω υπάρχουν τα locks τα οποία έρχονται να τηρήσουν τους κανόνες που είπαμε, αλλά για αυτά σε άλλο post.

    Autocommit Transactions ή Implicit Transactions

    Στον SQL Server έχω τα Autocommit Transactions ή Implicit Transactions που είναι και η default συμπεριφορά για κάθε sql statement που εκτελείται. Δηλαδή εκτελώ ένα insert statement αυτό θα είναι committed εφόσον δεν υπάρχει κάποιο λάθος, ενώ αν παρουσιαστεί σφάλμα αυτό είναι rollbacked.

    Για όσους θέλουν να απενεργοποιήσουν την παραπάνω συμπεριφορά του SQL Server γιατί τους φαίνεται ότι δεν είναι σωστή (επειδή έτσι νομίζουν γιατί το έχουν δει αλλού) υπάρχει η δυνατότητα με την εφαρμογή του IMPLICIT_TRANSACTION setting π.χ
    SET IMPLICIT_TRANSACTIONS ONINSERT / UPDATE / DELETE
    COMMIT / ROLLBACK







    Explicit Transactions

    Εάν θέλεις να έχεις δικά σου ελεγχόμενα transactions τότε θα πρέπει να ξεκινήσεις ένα δικό όπως στο παράδειγμα που ακολουθεί
    BEGIN TRAN….
    COMMIT / ROLLBACK
    Βέβαια θα πρέπει να είσαι προετοιμασμένος ώστε αν συμβεί κάτι να κάνεις rollback. Δεν θα σας κουράσω δείχνοντας σας πως αυτό γίνονταν πριν τον SQL Server 2005, θα σας δείξω πως γίνεται από τον 2005 και μετά που είναι και αρκετά πιο δομημένος τρόπος γραφής BEGIN TRY BEGIN TRAN
    ….
    COMMIT
    END TRY
    BEGIN CATCH
    ROLLBACK
    SELECT ERROR_NUMBER(), ERROR_MESSAGE()
    END CATCH



    Το θέμα φυσικά δεν εξαντλείτε εδώ είναι μεγάλο και θα επανέλθω σύντομα με ένα άλλο post που θα πηγαίνει περισσότερο σε βάθος.
×
×
  • Create New...