Jump to content

antonch

Administrators
  • Posts

    1030
  • Joined

  • Last visited

  • Days Won

    7

Blog Entries posted by antonch

  1. antonch
    Πριν μερικές μέρες μια ομάδα που είναι μέλη του Solid Quality Mentors οι 


    Ron Talmage,
    Aaron Johal,
    Allan Hirt,
    Herbert Albert,
    Antonio Soto,
    Greg Low,
    Dejan Sarka,
    Larry Barnes,
    Pablo Ahumada
    αρκετοί από αυτούς MVPs στον SQL Server έφτιαξαν ένα πόνημα 490 σελίδων!!! για το τι και πως θα κάνεις upgrade τον SQL Server σου σε SQL Server 2008 R2.

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


    Upgrade Planning and Deployment
    Management and Development Tools
    Relational Databases
    High Availability
    Database Security
    Full-Text Search
    Service Broker
    Transact-SQL Queries
    Notification Services
    SQL Server Express
    Analysis Services
    Data Mining
    Integration Services
    Reporting Services
    Other Microsoft Applications and Platforms
    Appendix 1: Version and Edition Upgrade Paths
    Appendix 2: Upgrade Planning Deployment and Tasks Checklist
    Αφιέρωσα αρκετό χρόνο για να το διαβάσω και πλέον το έχω κατατάξει στην συλλογή των πονημάτων που θεωρώ ευαγγέλια του SQL Server και δεν θα πρέπει να λείπει από κανένα DBA.

    Όποιος ενδιαφέρεται μπορεί να το κατεβάζει από εδώ.
  2. antonch
    Περιμένοντας να έρθουν συγγενείς και φίλοι σπίτι να μου ευχηθούν για την γιορτή μου, σκεφτόμουν πώς να ευχαριστήσω όλους που σήμερα είτε με email είτε με μηνύματα στο facebook ή στο messenger μου ευχήθηκαν χρόνια πολλά.
    Στο μυαλό μου ήρθε κάτι το οποίο το είδα πάλι να χρησιμοποιείται αλλά όχι και τόσο καλά το αντίθετο θα έλεγα. Aυτό δεν είναι από το sql server data type uniqueidentifier σαν primary key σε table.
    Ας δούμε λοιπόν τα πράγματα με την σειρά για να καταλάβουμε το πρόβλημα
    Φτιάχνουμε μια νέα βάση που θα γίνει το πείραμα μας
    USE master
    GO

    CREATE DATABASE test
    GO

    Σε αυτή φτιάχνουμε ένα πίνακα με την εξής δομή


    USE test
    GO
    CREATE TABLE t1
    (
    id UNIQUEIDENTIFIER NOT NULL PRIMARY KEY DEFAULT(NEWID()),
    aa INT IDENTITY NOT NULL,
    otherdata NCHAR(2000) DEFAULT (N'other data')
    )

    Ο πίνακας αυτός είναι έτσι φτιαγμένος ώστε να χωράνε δύο rows ανά page (1 page = 8K)


    Όπως βλέπετε έχω το πεδίο id το οποίο είναι uniquidentifier και το έχω ορίσει σαν primary key και επειδή αυτό πρέπει να παίρνει τιμές έχω βάλει σαν default την function NEWID() η οποία σε κάθε εκτέλεση της μας δίνει ένα μοναδικό GUID.


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


    Τέλος για φτιάξω τη λογική που ανέφερα παραπάνω να χωράνε δηλαδή δύο rows ανά σελίδα βάζω το πεδίο otherdata nchar(2000) ώστε να έχω ένα record length 4024 bytes απλά του βάζω μια default τιμή ώστε να έχει κάτι.


    Εκτελώντας το παραπάνω create command φτιάχνω τον πίνακα μου.


    Όπως είναι γνωστό ο SQL Server όταν φτιάχνω ένα πίνακα και του ορίζω το primary key αυτός φτιάχνει ένα unique index για να το υλοποιήσει. Στη περίπτωση δε που δεν υπάρχει ήδη clustered index αυτός είναι unique clustered index, όπως και στο παράδειγμα μας.


    Αυτό είναι εύκολα μπορούμε να το επιβεβαιώσουμε εκτελώντας την


    sp_helpindex t1
    GO

    index_name index_description index_keys
    ------------------------ ------------------------------------------------- ----------
    PK__t1__3213E83F7F60ED59 clustered, unique, primary key located on PRIMARY id

    Αφού λοιπόν έχουμε επιβεβαιώσει την υπαρξη του index ας έρθουμε να δούμε πως αυτό είναι φυσικά δομημένος, θυμίζω ότι ακόμα δεν έχουμε βάλει δεδομένα στον πίνακα μας. Αυτό μπορούμε να το δούμε εύκολα με τη χρήση ενός DMV το οποίο δεν είναι άλλο από το sys.dm_db_index_physical_stats.


    Έτσι εκτελώντας την παρακάτω εντολή


    SELECT index_id, avg_fragmentation_in_percent, page_count
    FROM sys.dm_db_index_physical_stats(DB_ID('test'),OBJECT_ID('t1'),1,NULL,'LIMITED')
    GO


    έχουμε το παρακάτω αποτέλεσμα


    index_id avg_fragmentation_in_percent page_count
    ----------- ---------------------------- --------------------
    1 0 0

    Παρατηρούμε ότι όλα τα πεδία μετά από index_id είναι μηδενικά και αυτό είναι σωστό καθώς δεν έχουμε ακόμα βάλει δεδομένα στο πίνακα μας.


    Ας έρθουμε όμως να βάλουμε δύο γραμμές σε αυτόν


    INSERT INTO t1 DEFAULT VALUES
    INSERT INTO t1 DEFAULT VALUES
    GO

    Και ας ξαναδούμε πως είναι τώρα ο index μας


    SELECT index_id, avg_fragmentation_in_percent, page_count
    FROM sys.dm_db_index_physical_stats(DB_ID('test'),OBJECT_ID('t1'),1,NULL,'LIMITED')
    GO

    Το αποτέλεσμα θα είναι το παρακάτω


    index_id avg_fragmentation_in_percent page_count
    ----------- ---------------------------- --------------------
    1 0 1

    Θα παρατηρήσουμε ότι το page_count είναι ίσο με το ένα. Άρα έχουμε δύο rows/page. Περίφημα μέχρι έδω!!!


    Ας βάλουμε ακόμα δύο γραμμές στον πίνακα μας


    INSERT INTO t1 DEFAULT VALUES
    INSERT INTO t1 DEFAULT VALUES
    GO

    Και ας ξαναδούμε την δομή του index μας.


    SELECT index_id, avg_fragmentation_in_percent, page_count
    FROM sys.dm_db_index_physical_stats(DB_ID('test'),OBJECT_ID('t1'),1,NULL,'LIMITED')
    GO

    Το αποτέλεσμα είναι το παρακάτω


    index_id avg_fragmentation_in_percent page_count
    ----------- ---------------------------- --------------------
    1 66,6666666666667 3

    Εδώ τώρα παρατηρώ κάτι πολύ περίεργο πρώτα από όλα ότι το row_count είναι ίσο με τρία!!! Και το avg_fragmentation_in_percent είναι ίσο με 66,6666666666667


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


    Πριν προχωρήσω στην αποκάλυψη του γιατί αυτό έχει συμβεί θα βάλω ακόμα μερικές γραμμές στο πίνακα μου ώστε στο σύνολο να είναι εκατό


    INSERT INTO t1 DEFAULT VALUES
    GO 96

    Ας έρθω να δω τι γίνεται με τον index μου


    SELECT index_id, avg_fragmentation_in_percent, page_count
    FROM sys.dm_db_index_physical_stats(DB_ID('test'),OBJECT_ID('t1'),1,NULL,'LIMITED')
    GO

    Το αποτέλεσμα είναι το παρακάτω και είναι άκρως απογοητευτικό


    index_id avg_fragmentation_in_percent page_count
    ----------- ---------------------------- --------------------
    1 98,4615384615385 65

    Το fragementation είναι στο θεό αλλά έχω 65 σελίδες αντί για 50 που θα έπρεπε να έχω. Οι 15 αυτές σελίδες διαφορά είναι μόνο για τις 100 γραμμές και φυσικά είναι ένα αρκετά σημαντικό performance penalty καθώς αυτό σημαίνει ΙΟ.


    Ας δούμε όμως τα δεδομένα μας


    SELECT * FROM t1
    GO

    Το αποτέλεσμα είναι το παρακάτω


    id aa otherdata
    ------------------------------------ ----------- -----------
    F028B3AF-1415-4081-A006-06DDA3D9FAD2 66 other data
    D58551AF-B632-4297-90A2-10D97AB854D0 51 other data
    A28C272C-1FA3-4506-8C62-1230E0E6926F 75 other data
    2B510EF2-E831-4CC0-BF7C-18B08C932934 24 other data
    394B5429-C8CD-4360-9768-18CE5775A8AE 73 other data
    5950B503-923D-4F33-9B21-1BEECBA1286C 79 other data
    16132ED8-B445-4217-B1E0-1E2D9FA40302 84 other data
    9887FCE3-F229-4236-AEA0-1EBFB5A73CA5 25 other data
    147DEAA4-8725-4797-9EBC-2B341889F9BD 57 other data
    BACC0008-F522-44EE-8A76-2E11BFAFCF80 33 other data
    5DEFA505-EFC3-44AB-9746-2F3AF2838E2D 20 other data
    5BD55DF8-757D-47FA-A53C-35E9AE7B428C 87 other data
    17F09983-33CF-4C48-8D06-36B64CDE3371 98 other data
    9EF858ED-E7B1-4A57-9491-38CB31F62844 90 other data
    3D26646B-DBFC-4D7C-8D9B-419BFF7D0350 47 other data
    7E04E79D-B728-4D8C-8F9E-47700C332433 97 other data
    8B4D0F05-B1F8-40BD-A32C-4D039BACB511 21 other data
    B065A2C4-C4C2-4375-93C8-4DDEF719A278 67 other data
    21C7F7A4-5120-4690-A5B8-5022BDE15233 7 other data
    56ACA620-B7C0-47D1-8821-53D3F2FBDA71 22 other data
    F3D55D7F-F089-424C-AFC8-53E5A76F2B23 31 other data
    2DF49ED6-3113-43AD-A7F4-556CC3328DD8 27 other data
    A7770D81-6818-4A9E-B3FA-57F682DAFFE9 63 other data
    02A840B7-B761-477D-9EB3-598A07A2401F 13 other data
    483B2183-5E03-4618-A39E-5BEF31470CFF 48 other data
    0C702D0F-E9D2-4E63-A5FB-5F66395CA97B 85 other data
    84A84DC9-4F78-4F98-A676-61B89B045A06 76 other data
    03CF97FA-0232-4107-A4FF-61E6FC01CEEA 28 other data
    B1BFB116-44B2-4D2E-BAF6-629854E236EC 64 other data
    95D0F80C-D07D-48B5-93EE-63C1CF67E1DF 95 other data
    BAA630CA-1A98-4DDA-B69B-650FF989B623 55 other data
    9FB18286-7BE6-4BBF-A75D-663961D11F30 71 other data
    D7D4335E-33B7-4FBB-995F-66E15D770284 41 other data
    EBF8C763-6425-4078-9BEF-6A7ADB618F49 58 other data
    2DF2516A-076C-458E-A61C-6A8D379A0F8A 78 other data
    85745D8E-122C-458A-A25C-6B203EEDDDD0 6 other data
    3B53D6A3-5E3D-4672-8FF5-6B725DD50094 77 other data
    F2A31C7E-F409-4FA6-A5AB-6F86F5F0CD21 42 other data
    A4318A22-9055-4FB1-B8BE-71497C1B203B 43 other data
    73923CE8-1F21-471D-BE58-7173C47B8633 68 other data
    76A8FFB8-5D92-4E55-9910-71D773935753 70 other data
    2EB0B127-FF41-478D-A8EC-727FCD0420AB 4 other data
    846E931D-A3E8-4885-BF15-73DCDD8BF06E 49 other data
    5426A25C-B419-4BD0-A8AE-76DEF2BD22B8 91 other data
    3925CE47-DDD1-4689-A4D6-7A8EB3004D63 86 other data
    8176A903-4C10-4DDC-97B4-7C0889442F12 23 other data
    0F436108-401D-40A7-8136-7ED7D91A6A2E 39 other data
    FF52B83A-8FF2-4706-80C3-7F00DE29E0B3 54 other data
    3E29EB19-E709-45F1-9CDD-7FDBBB489DE1 36 other data
    379DEFC6-7757-4A85-B82F-839F88C30AE8 96 other data
    AC7C56BF-3C5E-4EFA-B7A2-83D5E6D18D9A 15 other data
    7543C2EA-EC03-486B-9AB4-84483430E610 74 other data
    83AAC12E-F4C3-48A8-9BF9-8869E6390A4B 8 other data
    4F502BD4-5C99-4DC3-8352-88DA9591B27A 18 other data
    20C8395B-2E91-43C7-8FE1-8B4298BCD4B9 16 other data
    45989F49-574A-4438-A20F-8B609DBF7586 88 other data
    4EB6040C-AC60-42A0-94C9-8BB9542EF541 100 other data
    6476E0AB-7121-4DA2-8888-8CCD5C40CA87 12 other data
    3AA1154A-F650-44DC-B88E-91837A65E60D 19 other data
    228578BB-ABAF-4706-8CE7-93DE05FC3DF2 45 other data
    5A1689CC-7BDA-40A5-82FC-9650D58739AE 30 other data
    058F97B1-7AF7-4F32-801F-9AE3B284A9BB 80 other data
    07E106C4-0307-4ABE-AF02-9C734506BAC8 92 other data
    636CD13F-212B-4EAF-86C2-9EC3A8733DF6 40 other data
    23C8B3AE-77F2-45DC-BCE3-A0442EC0F8B3 52 other data
    E35160E1-FAD0-4CB3-9FCF-A2B2278EC4AA 61 other data
    758B3131-4329-46B2-A6D8-A2DC2A56ED8B 29 other data
    DA36FFC6-ADBD-4A38-B236-A3DFA3B7828B 94 other data
    98E8BC0F-4ABF-4CB5-BF9A-A4616CB51C7A 34 other data
    1A95A814-4D04-4C76-B378-A7E56CE4C685 82 other data
    D78D5EB7-9516-44E2-A196-A94205B35A8A 3 other data
    2E8B0887-CEB2-4487-B6F0-AE614E587488 59 other data
    67CA7AF8-18D4-45A3-9D53-AEB9A0EF97C8 99 other data
    A35AB10B-3F47-4184-A6FA-B8E38495A8C0 5 other data
    FFBCDA30-3134-49AB-8CD3-B9C512E50B0B 56 other data
    567EAD09-BF58-4027-9ABC-BCB62767DFE4 93 other data
    F0BAA52F-E5CA-42C0-A6D3-BFB81531CAFA 62 other data
    972F5A38-4F74-43E4-BCE6-C357E7D953D5 65 other data
    3258AB31-3A35-46BA-A053-C7686F3281BD 37 other data
    D3C00476-8582-4D61-B198-C7B5711BEF00 81 other data
    F521BBF6-770A-41D0-8FA5-C8E0684FD7D5 26 other data
    0BAE24EF-E7FE-42DD-BEA1-CA02A4024D5B 69 other data
    AA6BD0D8-EC8C-4B21-B21B-D429331C56B8 11 other data
    998FDC1B-7CAE-40DF-9AFA-DA3FD8CDCADB 89 other data
    4352A25D-A50B-42C3-A241-DC19BD7207D3 60 other data
    3F393EF3-3A26-4D36-BD00-DE9B9C63097E 38 other data
    B8A37EFF-5121-499E-AA22-E0ABE9C6293D 9 other data
    20B7C188-751F-4D90-8B9E-E1D4889A3795 1 other data
    CB2765CC-0FDA-423F-A5FE-E420A37BF2D5 72 other data
    2CE206A3-5481-4DC8-A725-E497611DD8BF 14 other data
    B1F04446-A9FB-4A64-8462-E5D02E4B5C71 17 other data
    89E50E9D-D1F9-488F-ADF0-EB13BD8B9D3F 83 other data
    3189B3B3-3892-4307-916F-EBC3E77573EE 44 other data
    3427F572-F535-4BF4-ADCC-EDC7E4C98E39 46 other data
    C93EDF08-35B4-430F-80B3-EE2605439DEE 2 other data
    15E0FBF2-18EF-41E4-938F-EFE7F0CA76F5 53 other data
    F665CAF8-C9BC-45D3-AD2B-F3E630FD8C5F 10 other data
    17C1CB7F-6C98-4A3D-9CD5-F883312B47C8 50 other data
    0191B624-C765-4C41-8FE3-FC0C07B82609 35 other data
    006D1851-23AC-4325-AD48-FE76F73F31BC 32 other data

    Αν προσεκτικά παρατηρήσουμε το αποτέλεσμα θα δούμε ότι τα rows έχουν ταξινομηθεί με βάση το id αλλά δεν έχουν μπει όμως το ένα κάτω από το άλλο καθώς αυτό φαίνεται από το πεδίο aa το οποίο μας δείχνει την σειρά εισαγωγής του row στο πίνακα.


    Αν μείνουμε μέχρι εδώ βγαίνει το συμπέρασμα ότι η χρήση του sql server data type σαν primary key σε ένα πίνακα είναι κακή, κάκιστη θα έλεγα επιλογή. Όμως δεν είναι έτσι τα πράγματα. Για αυτό ας κάνουμε ακόμα ένα πείραμα.


    Ας φτιάξουμε ένα ακόμα πίνακα όπως παρακάτω


    USE test
    GO

    CREATE TABLE t2
    (
    id UNIQUEIDENTIFIER NOT NULL PRIMARY KEY DEFAULT(NEWSEQUENTIALID()),
    aa INT IDENTITY NOT NULL,
    otherdata NCHAR(2000) DEFAULT (N'other data')
    )

    Αυτός είναι ακριβώς ίδιος με το προηγούμενο αλλά υπάρχει μια σημαντική διαφορά αντί να χρησιμοποιώ την NEWID() χρησιμοποιώ την NEWSEQUENTIALID() (είναι διαθέσιμη από την έκδοση του SQL Server 2005!!!).


    Aς επιβεβαιώσουμε ότι έχουμε τον index μας


    sp_helpindex t2
    GO

    index_name index_description index_keys
    ------------------------ ------------------------------------------------- ----------
    PK__t2__3213E83F0519C6AF clustered, unique, primary key located on PRIMARY id

    Και ας δούμε την δομή του index μας


    SELECT index_id, avg_fragmentation_in_percent, page_count
    FROM sys.dm_db_index_physical_stats(DB_ID('test'),OBJECT_ID('t2'),1,NULL,'LIMITED')
    GO

    index_id avg_fragmentation_in_percent page_count
    ----------- ---------------------------- --------------------
    1 0 0

    Ας βάλουμε τις δύο πρώτες γραμμές στο πίνακα μας


    INSERT INTO t2 DEFAULT VALUES
    INSERT INTO t2 DEFAULT VALUES
    GO

    Και ας δούμε την δομή του index μας


    SELECT index_id, avg_fragmentation_in_percent, page_count
    FROM sys.dm_db_index_physical_stats(DB_ID('test'),OBJECT_ID('t2'),1,NULL,'LIMITED')
    GO

    index_id avg_fragmentation_in_percent page_count
    ----------- ---------------------------- --------------------
    1 0 1

    Όλα όπως βλέπουμε είναι φυσιολογικά. Ας βάλουμε τις επόμενες δύο γραμμές στον πίνακα μας


    INSERT INTO t2 DEFAULT VALUES
    INSERT INTO t2 DEFAULT VALUES
    GO

    Και να δούμε τη δομή του index


    SELECT index_id, avg_fragmentation_in_percent, page_count
    FROM sys.dm_db_index_physical_stats(DB_ID('test'),OBJECT_ID('t2'),1,NULL,'LIMITED')
    GO

    index_id avg_fragmentation_in_percent page_count
    ----------- ---------------------------- --------------------
    1 50 2

    Όλα πάλι είναι φυσιλογικά έχω page_count ίσο με 2 που είναι και το φυσιλογικό μιας και έχω τέσσερεις γραμμές. Το avg_fragmentation_in_percent είναι υψηλό (50%) αλλά για να δούμε τι θα γίνει με αυτό αν βάλουμε στο πίνακα μας ακόμα 96 εγγραφές ώστε στο σύνολο να γίνουν 100?


    INSERT INTO t2 DEFAULT VALUES
    GO 96

    SELECT index_id, avg_fragmentation_in_percent, page_count
    FROM sys.dm_db_index_physical_stats(DB_ID('test'),OBJECT_ID('t2'),1,NULL,'LIMITED')
    GO

    index_id avg_fragmentation_in_percent page_count
    ----------- ---------------------------- --------------------
    1 4 50

    Όπως βλέπουμε αυτό έχει μειωθεί σημαντικά αλλά το περισσότερο σημαντικό είναι ότι ο αριθμός των σελίδων (page_count) έχει παραμείνει σωστός (50 σελίδες) δηλαδή 2 rows/page.


    Για να δούμε και τα δεδομένα μας στο πίνακα


    SELECT * FROM t2
    GO

    id aa otherdata
    ------------------------------------ ----------- ----------
    A6D5C824-7922-E011-A143-00155D020606 1 other data
    A7D5C824-7922-E011-A143-00155D020606 2 other data
    D439AA51-7922-E011-A143-00155D020606 3 other data
    D539AA51-7922-E011-A143-00155D020606 4 other data
    2C2FEF8C-7922-E011-A143-00155D020606 5 other data
    2D2FEF8C-7922-E011-A143-00155D020606 6 other data
    2E2FEF8C-7922-E011-A143-00155D020606 7 other data
    2F2FEF8C-7922-E011-A143-00155D020606 8 other data
    302FEF8C-7922-E011-A143-00155D020606 9 other data
    312FEF8C-7922-E011-A143-00155D020606 10 other data
    322FEF8C-7922-E011-A143-00155D020606 11 other data
    332FEF8C-7922-E011-A143-00155D020606 12 other data
    342FEF8C-7922-E011-A143-00155D020606 13 other data
    352FEF8C-7922-E011-A143-00155D020606 14 other data
    362FEF8C-7922-E011-A143-00155D020606 15 other data
    372FEF8C-7922-E011-A143-00155D020606 16 other data
    382FEF8C-7922-E011-A143-00155D020606 17 other data
    392FEF8C-7922-E011-A143-00155D020606 18 other data
    3A2FEF8C-7922-E011-A143-00155D020606 19 other data
    3B2FEF8C-7922-E011-A143-00155D020606 20 other data
    3C2FEF8C-7922-E011-A143-00155D020606 21 other data
    3D2FEF8C-7922-E011-A143-00155D020606 22 other data
    3E2FEF8C-7922-E011-A143-00155D020606 23 other data
    3F2FEF8C-7922-E011-A143-00155D020606 24 other data
    402FEF8C-7922-E011-A143-00155D020606 25 other data
    412FEF8C-7922-E011-A143-00155D020606 26 other data
    422FEF8C-7922-E011-A143-00155D020606 27 other data
    432FEF8C-7922-E011-A143-00155D020606 28 other data
    442FEF8C-7922-E011-A143-00155D020606 29 other data
    452FEF8C-7922-E011-A143-00155D020606 30 other data
    462FEF8C-7922-E011-A143-00155D020606 31 other data
    472FEF8C-7922-E011-A143-00155D020606 32 other data
    482FEF8C-7922-E011-A143-00155D020606 33 other data
    492FEF8C-7922-E011-A143-00155D020606 34 other data
    4A2FEF8C-7922-E011-A143-00155D020606 35 other data
    4B2FEF8C-7922-E011-A143-00155D020606 36 other data
    4C2FEF8C-7922-E011-A143-00155D020606 37 other data
    4D2FEF8C-7922-E011-A143-00155D020606 38 other data
    4E2FEF8C-7922-E011-A143-00155D020606 39 other data
    4F2FEF8C-7922-E011-A143-00155D020606 40 other data
    502FEF8C-7922-E011-A143-00155D020606 41 other data
    512FEF8C-7922-E011-A143-00155D020606 42 other data
    522FEF8C-7922-E011-A143-00155D020606 43 other data
    532FEF8C-7922-E011-A143-00155D020606 44 other data
    542FEF8C-7922-E011-A143-00155D020606 45 other data
    552FEF8C-7922-E011-A143-00155D020606 46 other data
    562FEF8C-7922-E011-A143-00155D020606 47 other data
    572FEF8C-7922-E011-A143-00155D020606 48 other data
    582FEF8C-7922-E011-A143-00155D020606 49 other data
    592FEF8C-7922-E011-A143-00155D020606 50 other data
    5A2FEF8C-7922-E011-A143-00155D020606 51 other data
    5B2FEF8C-7922-E011-A143-00155D020606 52 other data
    5C2FEF8C-7922-E011-A143-00155D020606 53 other data
    5D2FEF8C-7922-E011-A143-00155D020606 54 other data
    5E2FEF8C-7922-E011-A143-00155D020606 55 other data
    5F2FEF8C-7922-E011-A143-00155D020606 56 other data
    602FEF8C-7922-E011-A143-00155D020606 57 other data
    612FEF8C-7922-E011-A143-00155D020606 58 other data
    622FEF8C-7922-E011-A143-00155D020606 59 other data
    632FEF8C-7922-E011-A143-00155D020606 60 other data
    642FEF8C-7922-E011-A143-00155D020606 61 other data
    652FEF8C-7922-E011-A143-00155D020606 62 other data
    662FEF8C-7922-E011-A143-00155D020606 63 other data
    672FEF8C-7922-E011-A143-00155D020606 64 other data
    682FEF8C-7922-E011-A143-00155D020606 65 other data
    692FEF8C-7922-E011-A143-00155D020606 66 other data
    6A2FEF8C-7922-E011-A143-00155D020606 67 other data
    6B2FEF8C-7922-E011-A143-00155D020606 68 other data
    6C2FEF8C-7922-E011-A143-00155D020606 69 other data
    6D2FEF8C-7922-E011-A143-00155D020606 70 other data
    6E2FEF8C-7922-E011-A143-00155D020606 71 other data
    6F2FEF8C-7922-E011-A143-00155D020606 72 other data
    702FEF8C-7922-E011-A143-00155D020606 73 other data
    712FEF8C-7922-E011-A143-00155D020606 74 other data
    722FEF8C-7922-E011-A143-00155D020606 75 other data
    732FEF8C-7922-E011-A143-00155D020606 76 other data
    742FEF8C-7922-E011-A143-00155D020606 77 other data
    752FEF8C-7922-E011-A143-00155D020606 78 other data
    762FEF8C-7922-E011-A143-00155D020606 79 other data
    772FEF8C-7922-E011-A143-00155D020606 80 other data
    782FEF8C-7922-E011-A143-00155D020606 81 other data
    792FEF8C-7922-E011-A143-00155D020606 82 other data
    7A2FEF8C-7922-E011-A143-00155D020606 83 other data
    7B2FEF8C-7922-E011-A143-00155D020606 84 other data
    7C2FEF8C-7922-E011-A143-00155D020606 85 other data
    7D2FEF8C-7922-E011-A143-00155D020606 86 other data
    7E2FEF8C-7922-E011-A143-00155D020606 87 other data
    7F2FEF8C-7922-E011-A143-00155D020606 88 other data
    802FEF8C-7922-E011-A143-00155D020606 89 other data
    812FEF8C-7922-E011-A143-00155D020606 90 other data
    822FEF8C-7922-E011-A143-00155D020606 91 other data
    832FEF8C-7922-E011-A143-00155D020606 92 other data
    842FEF8C-7922-E011-A143-00155D020606 93 other data
    852FEF8C-7922-E011-A143-00155D020606 94 other data
    862FEF8C-7922-E011-A143-00155D020606 95 other data
    872FEF8C-7922-E011-A143-00155D020606 96 other data
    882FEF8C-7922-E011-A143-00155D020606 97 other data
    892FEF8C-7922-E011-A143-00155D020606 98 other data
    8A2FEF8C-7922-E011-A143-00155D020606 99 other data
    8B2FEF8C-7922-E011-A143-00155D020606 100 other data

    Αν παρατηρήσουμε τα δεδομένα θα δούμε ότι αυτά είναι ταξινομημένα με το id αλλά έχουμε σωστή και την σειρά καταχωρήσης, δηλαδή το πρώτο record μπήκε πρώτο και το id στην ταξινόμηση είναι πρώτο το δεύτερο το τρίτο, …, το εκατοστό.


    Όμως αυτό δεν είναι ο λόγος που τώρα είναι όλα καλά.


    Όπως γνωρίζουμε στο leaf level του index είναι ο index ταξινομημένος. Επίσης επειδή ο index μας είναι clustered στην ουσία το leaf level και τα data pages είναι το ίδιο και το αυτό.


    Στην πρώτη περίπτωση με την χρήση της NEWID(), η οποία κάθε φορά επιστρέφει ένα τυχαίο GUID, σαν default value έχω το εξής φαινόμενο


    Με το που βάζω το πρώτο record αυτό μπαίνει στη σελίδα πχ 1 το δεύτερο μπαίνει και αυτό σε αυτή τη σελίδα, έτσι η σελίδα μας είναι ως εξής


    id aa otherdata
    ------------------------------------ ----------- ----------------------
    20B7C188-751F-4D90-8B9E-E1D4889A3795 1 other data
    C93EDF08-35B4-430F-80B3-EE2605439DEE 2 other data

    Όταν πάμε να βάλουμε το τρίτο record το οποίο είναι το παρακάτω


    D78D5EB7-9516-44E2-A196-A94205B35A8A 3 other data

    Το οποίο πρέπει να μπει πριν από το πρώτο έτσι πρέπει να γίνει page split στην πρώτη σελίδα και επειδή δεν έχουμε ορίζει κάποιο fillfactor στον index (default ίσο 0 που σημαίνει ότι αφήνει χώρο ώστε να μπορεί να μπει ακόμα μία έγγραφή) δημιουργούνται τρεις σελίδες όπου η κάθε μια έχει από ένα record


    Page 1
    id aa otherdata
    ------------------------------------ ----------- ------------
    D78D5EB7-9516-44E2-A196-A94205B35A8A 3 other data
    Page 2
    id aa otherdata
    ------------------------------------ ----------- ------------
    20B7C188-751F-4D90-8B9E-E1D4889A3795 1 other data
    Page 3
    id aa otherdata
    ------------------------------------ ----------- ------------
    C93EDF08-35B4-430F-80B3-EE2605439DEE 2 other data

    Βάζοντας και την τέταρτη εγγραφή η δομή του index είναι η παρακάτω


    Page 1
    id aa otherdata
    ------------------------------------ ----------- ---------------
    D539AA51-7922-E011-A143-00155D020606 4 other data
    D78D5EB7-9516-44E2-A196-A94205B35A8A 3 other data
    Page 2
    id aa otherdata
    ------------------------------------ ----------- ---------------
    20B7C188-751F-4D90-8B9E-E1D4889A3795 1 other data
    Page 3
    id aa otherdata
    ------------------------------------ ----------- --------------
    C93EDF08-35B4-430F-80B3-EE2605439DEE 2 other data

    Εξου και το αποτέλεσμα που πήραμε και είδαμε ότι είχαμε 3 σελίδες. Αυτό συμβαίνει σε όλες τις άλλες εγγραφές με την ίδια λογική και έτσι έχουμε το τελικό αποτέλεσμα με το μεγάλο fragmentation και τις 65 σελίδες.


    Στο δεύτερο πίνακα όμως δεν συμβαίνει κάτι τέτοιο καθώς η NEWSEQUENTIALID() δίνει σειριακά GUIDs. Έτσι δεν έχουμε ούτε ουσιαστικά μεγάλο fragmentation ούτε παραπάνω αριθμό σελίδων.


    Συμπέρασμα


    Το πεδίο uniqueidentifier δεν έχει απολύτως κανένα πρόβλημα να είναι primary key σε ένα πίνακα (κατ’ επέκταση θα έλεγα ότι δεν έχει κανένα πρόβλημα να είναι clustered key) ΑΡΚΕΙ να γεμίζει με την NEWSEQUENTIALID() function και όχι με την NEWID() function.
  3. antonch
    Για να δείτε την μαγνητοσκόπηση κάντε click εδώ
    ή επισκευθείτε το www.techdays.gr και αναζητήστε την με το tag SQL Saturday Nights
  4. antonch
    Τελικά ο Αη Βασίλης ήρθε και για μένα. Για δεύτερη χρονιά μου απονεμήθηκε ο τίτλος του MVP στον SQL Server. Αυτό σημαίνει περισσότερες ευθύνες για μένα, αλλά ευχάριστες.

    Η χρονιά αυτή θα συνεχιστεί με περισσότερη δράση και περισσότερα SQL Saturday Nights.

    Καλή Χρονιά σε όλους και σας ευχαριστώ για την υποστήριξη
  5. antonch
    To recording μπορείτε να το δείτε εδώ
     
    Σας έλειψαν το ξέρω, και εμένα.
    Αλλά από το τελευταίο έγιναν πολλά, IT PRO|DEV Connections 2010, έπεσε πολύ δουλειά και πολλά ακόμα, που δεν μου έδωσαν χρόνο να διοργανώσω ένα νέο. Όμως ποτέ δεν είναι αργά. Έτσι λέω να κάνουμε ένα το επόμενο Σάββατο 18/12/2010 την γνωστή ώρα 22:30 και με θέμα «Security in SQL Server 2008 R2»
    Για να συνδεθείτε στο event πατήστε εδώ
    Το επόμενο θα είναι με την νέα χρονιά.
  6. antonch
    ALTER PROCEDURE, CONTINUE, IGNORE,money and smallmoney, AFTER, BEFORE,
    INDEXKEY_PROPERTY, CAST and CONVERT,
    GROUP BY, IDENTITY (Function), DEFERRED,
    BACKUP, nchar and nvarchar, COMPUTE,
    EXECUTE, UPDATE STATISTICS, INCLUDE,
    datetime and smalldatetime, ISNULL, ROUTINE,
    ROLLBACK TRANSACTION, IS_MEMBER, BETWEEN
     

    By Michael J. Swart  

    Source : http://michaeljswart.com/?tag=sql-poem
  7. antonch
    Κατά την διάρκεια του IT PRO | DEV CONNECTIONS 2010 και ειδικότερα στην παρουσίαση του Γιώργου του Καπνιά αλλά και την δική μου είχα την ευκαιρία να κάνω μερικές ερωτήσεις ώστε αυτός που θα απαντήσει να πάρει κάποιο δώρο.

    Μία από αυτές τις ερωτήσεις που έκανα ήταν αν γνώριζε κανείς το codename του SQL Server 7. Επειδή δεν το γνώριζε κανείς αποφάσισα να φτιάξω αυτό το post ώστε να αναφέρω τα codenames όλων των εκδόσεων του SQL Server αλλά και διαφόρων επιμέρους τμημάτων του. Έτσι έχουμε την παρακάτω λίστα

     







    Έτος



    Codename



    Release




    1989



    -



    SQL Server 1.0 (16bit)




    1991



    -


    SQL Server 1.1 (16bit)




    1993



    SQLNT


    SQL Server 4.2


    The first version of Microsoft SQL Server that was designed for Windows NT




    1995



    SQL95



    SQL Server 6.0





     


    Starfighter



    SQL Server Enterprise Manager


    Management tool, included in SQL Server 6.0 - SQL Server 2000




    1996



    Hydra



    SQL Server 6.5




    1998



    Sphinx



    SQL Server 7.0




    1999



    Plato



    SQL Server 7.0 OLAP Services




    2000



    Shiloh



    SQL Server 2000 (32-bit)




    2003



    Liberty



    SQL Server 2000 (64-bit)




    2004



    Rosetta



    SQL Server Reporting Services




    2005



    Yukon



    SQL Server 2005




    2005



    Laguna



    SQL Server 2005 Mobile Edition




    2008



    Katmai



    SQL Server 2008




    2008



    Blue



    SQL Report Designer 2.0




    2010



    Kilimanjaro



    SQL Server 2008 R2




    ????


    Denali


    SQL Server ????
  8. antonch
    Επιτέλους η στιγμή την οποία περίμενα εδώ και 1 χρόνο έφτασε.
    Μπορώ να σπάσω την σιωπή μου και να ανακοινώσω ότι πλέον είναι διαθέσιμη σε όλους η νέα έκδοση του SQL Server την οποία μπορείτε να βρείτε στο παρακάτω link
    http://www.microsoft.com/downloads/en/details.aspx?FamilyID=6a04f16f-f6be-4f92-9c92-f7e5677d91f9
    Πολλά έχουν αλλάξει, ακόμα περισσότερα έχουν προσθεθεί. Για όλα αυτά όμως θα μου δωθεί η ευκαιρία να σας μιλήσω σε posts που θα ακολουθήσουν.
  9. antonch
    Ολοκληρώθηκε το meeting και το recording αυτού μπορείτε να το βρείτε στα παρακάτω σήμεια
    https://www311.livemeeting.com/cc/mvp/view?id=DSZT9W http://www.techdays.gr --------------------------------------------------------------------------------------------------------
    Συνεχίζουμε στο ρυθμό μας, ελπίζοντας αυτή η προσπάθεια να σας αρέσει, με το 3ο Saturday SQL Night και θεματολογία Backup & Restore (έπειτα με απαίτηση αρκετών από εσάς ).
    Παρακάτω σας δίνω τα στοιχεία του meeting και ελπίζω να δω τους περισσότερους από εσάς.
    Ημερομηνία & Ώρα : 06/11/2010 22:30 μμ
    Attendee URL: https://www.livemeeting.com/cc/mvp/join?id=DSZT9W&role=attend&pw=p7%28pCxwWq
    Meeting ID: DSZT9W
    Attendee Entry Code: p7(pCxwWq
    Duration: 2 hours
    Μέχρι τότε να είσαι όλοι καλά και να προσέχετε τον εαυτό σας.
  10. antonch
    Σήμερα ανέβαζα ένα project σε production το οποίο ήταν ένα Web Application σε .ΝΕΤ όπου χρησιμοποιούσαμε το Report Viewer Control για να δείχνουμε τα reports που η εφαρμογή έχει.
    Ενώ σε όλα τα στάδια ανάπτυξης και τεστ δεν είχαμε κάποιο θέμα μόλις ανέβηκε στην παραγωγή άρχισαν τα τηλέφωνα από τον πελάτη και μου στέλνουν και ένα mail με ένα screen dump όπου το control αυτό δεν έκανε τίποτα τα είχε δει όλα.
    Η εικόνα του control ήταν η παρακάτω

    Φυσικά ο IIS της παραγωγής ήταν ο 7 στο οποίο έχουν γίνει θεαματικές αλλαγές. Έτσι όταν βάζεις ένα control σε μια web page to Visual Studio παει και βάζει μέσα στο web.config το παρακάτω entry
    system.web>
    httpHandlers>
    add path="Reserved.ReportViewerWebControl.axd" verb="*" type="Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" validate="false"/>
    httpHandlers>
    system.web>

     


    Ο IIS 7 δεν μπορεί να το διαβάσει καθώς το httpHandlers section δεν είναι εκει πλέον αλλα στο . Δυστυχώς το VS 2008 πειράζει το web.config με την λογική του IIS 6.0.


    Θα πρέπει λοιπόν για να διορθωθεί το θέμα αυτό είτε από το management tool του IIS 7 να βάλει το http Handler είτε να αλλάξεις εσύ το web.config όπως παρακάτω


    system.webServer>
    handlers>
    add name="ReportViewerWebControl" path="Reserved.ReportViewerWebControl.axd" verb="*" type="Microsoft.Reporting.WebForms.HttpHandler, Microsoft.ReportViewer.WebForms, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
    handlers>
    system.webServer>
  11. antonch
    Επειδή μάλλον το πρώτο άρεσε είπα να κάνω και το δεύτερο σύντομα.
    Έτσι λοιπόν θα συνεχίσουμε από εκεί που μείναμε δηλαδή την δημιουργία μιας database με πολλά tips για αυτούς που θέλουν να μάθουν να σχεδιάζουν σωστά μια database στον SQL Server.
    Φυσικά αυτό από πίσω κρύβει αρκετή δόση αρχιτεκτονικής.
    Παρακάτω θα σας δίνω τα στοιχεία του meeting και ελπίζω να δω τους περισσότερους από εσάς.
    Ημερομηνία & Ώρα : 23/10/2010 22:30 μμ
    Attendee URL: https://www.livemeeting.com/cc/mvp/join?id=WP7JZ9&role=attend&pw=s%26Dr5%29JWD
    Meeting ID: WP7JZ9
    Attendee Entry Code: s&Dr5)JWD
    Duration: 2 hours
    Μέχρι τότε να είσαι όλοι καλά και να προσέχετε τον εαυτό σας.
    Εδώ θα βρείτε την μαγνητοσκοπημένη παρουσίαση
  12. antonch
    Χειμώνιασε και νομίζω ότι είναι καιρός να αρχίσουμε .
    Βασανίστηκα αρκετά για να επιλέξω θέμα. Είχα να επιλέξω μεταξύ πολλών θεμάτων. Κάποια ήταν υψηλής δυσκολίας και ίσως φίλοι που δεν έχουν την απαιτούμενη εμπειρία στον SQL Server θα είχαν δυσκολίες στην παρακολούθηση. Κάποια άλλα εύκολα και οι έμπειροι φίλοι να τα έβρισκαν ανιαρά. Δύσκολη απόφαση.
    Έτσι πήρα μια απόφαση που πιστεύω ότι είναι η πιο δίκαιη. Θα ξεκινήσουμε από τα βασικά ώστε μέσα στα πρώτα 4-5 μαθήματα να έρθουν οι «μη έμπειροι» σε μια κατάσταση όμοια με τους «έμπειρους» .
    Στο 1ο μάθημα θα ξεκινήσουμε από την εγκατάσταση του SQL Server και θα φτάσουμε μέχρι την δημιουργία και την αρχιτεκτονική μιας database. Απλό θέμα αλλά νομίζω ότι είναι απαραίτητο για αρχή. Εξάλλου θα είναι και πιλότος για το διαδικαστικό μέρος της προσπάθειας αυτής.
    Παρακάτω θα σας δίνω τα στοιχεία του meeting και ελπίζω να δω τους περισσότερους από εσάς.
    Ημερομηνία & Ώρα : 16/10/2010 22:30 μμ
    Attendee URL: https://www.livemeeting.com/cc/mvp/join?id=ZR29ZM&role=attend&pw=5Kpf%5C%7B22w
    Meeting ID: ZR29ZM
    Attendee Entry Code: 5Kpf\{22w
    Duration: 2 hours
    Μέχρι τότε να είσαι όλοι καλά και να προσέχετε τον εαυτό σας.
  13. antonch
    Αναζητώντας τρόπους για να εκτονώσω την όρεξη μου για εκπαίδευση αποφάσισα να κάνω κάτι μιας και δεν βλέπω να γίνεται κάτι άλλο αυτό τον καιρό.
    Η ιδέα μου ήρθε έτσι ξαφνικά σήμερα το βράδυ ακούγοντας την βροχή να πέφτει.
    Σκέφτηκα ότι τώρα που χειμωνιάζει και οι περισσότεροι θα είμαστε χωμένοι μέσα στην ζεστασιά του σπιτιού μας τα βράδια του Σαββάτου να διοργανώσω εκπαιδευτικά live meetings με θέματα που αφορούν τον SQL Server (και Visual Studio άμα θέλετε).
    Το concept όπως το έχω σκεφτεί έχει ως εξής:
    Κάθε δεύτερο Σάββατο γύρω στις 23:00 το βράδυ που όλοι θα είστε χαλαροί μιας και θα έχετε βάλει τις πυτζάμες σας, τις παντόφλες σας, και τα παιδία για ύπνο να βρισκόμαστε ηλεκτρονικά και να σας κάνω εκπαίδευση πάνω στο θέμα το οποίο είτε θα έχω επιλέξει είτε θα μου έχετε προτείνει εσείς.
    Φυσικά όλα αυτά θα είναι δωρεάν και θα έχει διάρκεια περίπου 2 ώρες.
    Επειδή δεν ξέρω αν αυτό θα έχει ανταπόκριση θα ήθελα τη γνώμη σας ώστε αν δω ότι είναι θετική να προχωρήσω στην διοργάνωση του.
    Για το λόγο αυτό θα ήθελα να ποστάρετε την απάντηση σας στο παρόν ποστ και φυσικά αν έχετε κάποιο θέμα που θα θέλατε να παρουσιαστεί.
    Επίσης καλό θα ήταν αυτό να το διαδώσετε και στους φίλους σας ώστε να μπουν και αυτοί να ψηφίσουν και φυσικά να θέσουν το θέμα τους
    Φιλικά
    Αντώνης
    Υ.Γ Θα παρακαλούσα να έχω τις απαντήσεις εδώ και όχι κάπου άλλου ώστε να τις έχω συγκεντρωμένες σε ένα σημείο
  14. antonch
    Βλέποντας μέσα από το forum μας διάφορες συζητήσεις σχετικά με το θέμα του μεγέθους του transaction log (T-Log) διαπίστωσα ότι υπάρχει ένα θολό τοπίο γύρω από το θέμα disaster recovery (backup - restore) πάνω στον SQL Server.
    Πήρα την απόφαση να γράψω για αυτό το θέμα ώστε να το ξεκαθαρίσω μια και καλή διότι είναι τόσο απλό και τόσο δυνατό που είναι αμαρτία από το Θεό να παιδεύεται ο κόσμος.
    Πριν ξεκινήσω να παρουσιάζω το θέμα θα πρέπει να ξεκαθαρίσω, και θα ήθελα αυτό να το έχετε σαν αρχή, στον SQL Server παίρνουμε SQL Server Backup και όχι οτιδήποτε άλλο.
    Μέχρι σήμερα δεν σας έχω πει τίποτα για Ευαγγέλια, όσοι έχετε κάνει μάθημα μαζί μου όμως ξέρετε, σήμερα θα σας πω ένα από αυτά.
    Επίσης θεωρώ φρόνιμο να ρίξετε πρώτα μια ματιά σε αυτό το post μου διότι θα σας φανεί χρήσιμο για να κατανοήσετε το παρόν άρθρο.
    Database Recovery Models
    Πρώτα από όλα θα πρέπει να καταλάβουμε τι είναι τα database recovery models, τι κάνουν, ποια είναι και πως επηρεάζουν το disaster recovery strategy που θα ακολουθήσουμε.
    Simple Recovery Model
    Είναι το απλούστερο μοντέλο το οποίο μπορεί κάποιος να επιλέξει σε μια βάση δεδομένων.
    Ενδείκνυται για :
    1. μικρές βάσεις δεδομένων,
    2. για βάσεις που έχουν μικρό αριθμό αλλαγών (transactions),
    3. για τις περιπτώσεις που θέλουμε να έχουμε μικρό μέγεθος στο T-Log file,
    4. για βάσεις που είναι read-only,
    5. για τις βάσεις που είναι σε φάση development ή δουλεύουν developers με αυτές για την κατασκευή εφαρμογών.
    Το συγκεκριμένο μοντέλο δουλεύει με τον εξής τρόπο, κάθε φορά που γίνεται διαδικασία checkpoint ή φτάνει να γεμίσει το φυσικό αρχείο του T-Log file γίνεται αυτόματα truncate με αποτέλεσμα να επαναχρησιμοποιείτε ο εσωτερικά ελεύθερος χώρος.
    Το μειονέκτημα στο μοντέλο αυτό είναι ότι μπορείς να γυρίσεις στον τελευταίο full backup που έχεις πάρει στην περίπτωση που η βάση σκάσει.
    Full Recovery Model
    Είναι το default recovery model. Όλα τα transactions που γίνονται στην βάση καταγράφονται στην λεπτομέρεια τους σε επίπεδο data page και row και αυτό έχει σαν αποτέλεσμα να χρειάζεται περισσότερος χώρος για το T-Log file. Το πλεονεκτήματα του είναι ότι στις περιπτώσεις που έχω πτώση της βάσης μπορώ να γυρίσω ακριβώς στο σημείο της πτώσης της χάνοντας μόνο τα transactions που την στιγμή της πτώσης ήταν σε εξέλιξη δηλαδή δεν είχαν γίνει commit!.
    Bulk-Logged Recovery Model
    Είναι ίσως αυτό που πολλοί DBA δεν το έχουν καταλάβει πως δουλεύει!. Αυτό κάνει ακριβώς ότι κάνει και το Full Recovery Model με μια σημαντική διαφορά. Καταγράφει τα πάντα σε επίπεδο extent (8 συνεχόμενες σελίδες). Αυτό έχει σαν αποτέλεσμα να μπορώ να γυρίσω πάλι στο σημείο της πτώσης της βάσης αλλά χρειάζομαι περισσότερο χρόνο για να έρθει αυτή σε κατάσταση online.
    Για να γίνει κατανοητό αυτό ας πάρουμε σαν παράδειγμα το εξής:
    Έστω ότι έχω μια βάση που είναι σε Full Recovery Model και φτιάχνω ή συντηρώ κάποιον index που έχω σε αυτή. Αφού έχει τελειώσει η εργασία αυτή έστω ότι έχω πτώση της βάσης. Όταν θα κάνω restore η εργασία αυτή θα είναι έτοιμη. Εάν όμως είμαι σε Bulk-Logged Model τα πράγματα είναι λίγο διαφορετικά. Για να το κάνω πιο κατανοητό ας πούμε ότι καταγράφεται η ενέργεια και όχι το αποτέλεσμα της. Έτσι όταν θα κάνω restore θα πρέπει να ξανακάνει πάλι την ενέργεια αυτή, που όπως γίνεται εύκολα αντιληπτό από την φύση της ενέργειας θα πάρει χρόνο για να την ολοκληρώσει.
    Σε αυτό το μοντέλο όλες οι bulk εργασίες γίνονται logged με το ελάχιστο δυνατό τρόπο. Τέτοιες εργασίες είναι:
    · Bulk imports of data (BCP, BULK INSERT, OPENROWSET with BULK clause)
    · BLOB operations ( WRITETEXT, UPDATETEXT)
    · SELECT INTO statements
    · CREATE/ALTER INDEX, ALTER INDEX REBUILD, DBCC REINDEX
    Το μοντέλο αυτό είναι ιδανικό για περιπτώσεις που έχω data warehouses και βάσεις με μεγάλο όγκο από bulk εργασίες. Το μειονέκτημα του είναι δεν μπορώ να γυρίσω σε συγκεκριμένο σημείο (point-in-time) το οποίο όμως θα δούμε παρακάτω τι είναι αυτό.
    SQL Server Backup Types
    Για να δούμε όμως τις δυνατές επιλογές που έχουμε για backup στον SQL Server. Επίσης θα πρέπει να επισημάνω, κάτι το οποίο ισχύει για όλα τους τύπους, ότι μπορώ να πάρω backup ενώ υπάρχει κόσμος και δουλεύει πάνω στην βάση μου (το λέω γιατί μπορείς κάποιος να μην το έχει καταλάβει ότι αυτό γίνεται). Μπορώ να έχω όσα backups θέλω μέσα στην ημέρα αν αυτό δεν μου δημιουργεί προβλήματα απόδοσης στην βάση κατά τη στιγμή που γίνεται αυτή backup. Ναι υπάρχει κάποιο πέναλτι το οποίο επηρεάζεται από πολλούς παράγοντες όπως ταχύτητα μαγνητικών μέσων, μέγεθος βάσης και τύπος του backup.
    Full Backup
    Είναι η βάση για όλες τις άλλες επιλογές που έχω για backup στον SQL Server. Με άλλα λόγια δεν μπορώ να κάνω πχ Differential, Transaction, Tail-Log κλπ εάν δεν έχω πάρει έστω ένα Full Backup. Στην ουσία παίρνει τα πάντα backup με τον έξης τρόπο. Πρώτα κάνει την διαδικασία checkpoint όπου κατεβάζει με αυτή όλα τα data pages της βάσης, που παίρνω backup, από την buffer cache στον δίσκο και μετά ρουφάει σαν σκούπα hoover τα αρχεία από δίσκο και τα βάζει στο backup μου. Ο χρόνος εκτέλεσης μιας τέτοιας εργασίας είναι πάντα σχετικός με το μέγεθος το δεδομένων μου. Το μέγεθος του backup είναι πάντα το πραγματικό μέγεθος των δεδομένων που έχω στην βάση και όχι το φυσικό μέγεθος των αρχείων που υπάρχουν στο δίσκο. Εάν θέλει κάποιος να κάνει εκτίμηση του μεγέθους του Full Backup σε μια βάση του δεν έχει από το να εκτελέσει την sp_spaceused stored procedure και θα πάρει την απάντηση στο ερώτημα του. Επίσης θα πρέπει να γνωρίζουμε ότι Full Backup μπορώ να πάρω με οποιοδήποτε επιλεγμένο Recovery Model έχω στην βάση μου. Εν κατακλείδι ΠΑΝΤΑ FULL BACKUP είναι η ΒΑΣΗ ΟΛΩΝ.
    Στην ουσία το επόμενο full backup που θα πάρω περιέχει μέσα του όλα τα προηγούμενα.
    Differential Backup
    Για να πάρω Differential Backup πρέπει να έχω πάρει Full Backup. Μπορώ να πάρω diffrential backup με όλα τα recovery models. Κάθε τέτοιου τύπου backup περιέχει ΟΛΕΣ τις αλλαγές που έχουν γίνει από το τελευταίο Full Backup που έχω πάρει. Στην ουσία κάθε νέο differential backup "καταργεί" όλα τα προηγούμενα diffential backups.
    Ας πάρουμε ένα παράδειγμα. Έστω ότι έχω πάρει full backup στις 05:00 και στις 10:00 παίρνω differential backup. Αυτό περιέχει ότι έχει γίνει από τις 05:00 μέχρι τις 10:00. Εάν στις 13:00 ξαναπάρω differential αυτό περιέχει ότι έχει γίνει από τις 05:00 μέχρι τις 13:00.
    Ελπίζω αυτό να έγινε κατανοητό διότι αρκετοί συνάδελφοι πιστεύουν ότι το κάθε differential περιέχει τις αλλαγές από το τελευταίο backup.
    Ιδανικό σενάριο για μεγάλες βάσεις που το full backup παίρνει χρόνο. Επίσης το χρησιμοποιούμε και για να μειώσουμε τον αριθμό των αρχείων αλλά και το χρόνο που θα χρειαστούμε σε περίπτωση που θελήσουμε να κάνουμε restore.
    Transaction Log Backup
    Αυτός ο τύπος backup παίζει μόνο εφόσον στην βάση μου έχω FULL ή BULK-LOGGED Recovery Model.
    Φυσικά για να πάρω T-Log backup θα πρέπει να έχω πάρει ένα full backup. Κάθε T-Log backup περιέχει τα transactions που έχουν γίνει στην βάση μου για το χρονικό διάστημα από το τελευταίο full ή differential ή t-log backup. Ο χρόνος που απαιτείται για αυτό συνήθως είναι μικρός και το πέναλτι στην απόδοση σχεδόν ασήμαντο. Επίσης θα πρέπει να τονιστεί ότι EINAI ΤΟ ΜΟΝΑΔΙΚΟ BACKUP ΠΟΥ ΚΑΝΕΙ TRUNCATE TO LOG FILE. (δείτε το άρθρο μου "Ο θαυμαστός κόσμος του Transaction Log")
    Ας πάρουμε ένα παράδειγμα. Έστω ότι έχω πάρει full backup στις 05:00 και στις 07:00 παίρνω t-log backup αυτό περιέχει τα transactions που έχουν γίνει από τις 05:00 έως τις 07:00. Εάν στις 09:00 πάρω ξανά t-log backup αυτό θα περιέχει τα transactions που έχουν γίνει από τις 07:00 έως τις 09:00.
    Προσοχή: Το κάθε t-log backup χρειάζεται την προηγούμενη βάση του για να γίνει restore. Εάν για παράδειγμα χάσω το t-log backup που πήρα στις 07:00 δεν θα μπορέσω να κάνω restore αυτό που πήρα στις 09:00 αυτό στην ορολογία του SQL Server το ονομάζουμε transaction log chain.
    Tail-Log Backup
    Ένα tail-log backup είναι στην ουσία ένα t-log backup το οποίο περιέχει το κομμάτι του log το οποίο δεν έχει παρθεί backup. Μα θα μου πει κάποιος αυτό δεν είναι t-log backup; Όχι ακριβώς. Για να γίνει κατανοητό θα πάρουμε ένα παράδειγμα. Έστω ότι κάθε μέρα στις 05:00 κάνω full backup και κάθε 2 ώρες από εκεί και μετά t-log backup. Έστω ότι στις 11:30 η βάση μου αποδημεί εις τον Κύριο. Σύμφωνα με αυτά που έχουμε πει μέχρι τώρα στα χέρια μου έχω backups που όταν θα τα κάνω restore θα με γυρίσουν στις 11:00 άρα χάνω ότι έχω κάνει από 11:00-11:30. Ξαναλέω ότι η βάση είναι off. Πριν αρχίσω να κάνω restore θέλω να βάλω στην τσέπη μου αυτό το μισάωρο. Εάν τα καταφέρω τότε θα είμαι σε θέση να γυρίσω στις 11:30. Και τώρα κάποιος θα πει, "και γιατί δεν προσπαθώ να πάρω t-log backup;". Αυτό δεν μπορεί να γίνει διότι πρέπει για μια ακόμα φορά να τονίσουμε ότι κάθε φορά που πάω να πάρω t-log backup αυτός κάνει διαδικασία checkpoint αλλά επειδή η βάση είναι off δεν μπορεί να πάρει και backup. Έτσι παίρνω tail-log backup όπου ρουφάει σαν σκουπα hoover το log file χωρίς να κάνει διαδικασία checkpoint. Μάλιστα από την έκδοση του SQL Server 2005 και σας ζητάει σε κάποιες περιπτώσεις να πάρετε πρώτα tail-log backup και μετά να κάνετε restore. Θα σας εξηγήσω παρακάτω τον τρόπο με τον οποίο μπορείτε να κάνετε κάτι τέτοιο.
    File/Filegroup Backup
    Είναι το δυσκολότερο σε υλοποίηση backup στον SQL Server μιας και πρέπει να ξέρεις αρκετά πράγματα για το πώς είναι δομημένη η βάση στην οποία θέλεις να το εφαρμόσεις. Ας πάρουμε ένα παράδειγμα για να το κατανοήσουμε καλύτερα. Έστω ότι έχω μια βάση που έχει 2 data files και 1 log file, αν και το log δεν με ενδιαφέρει στο συγκεκριμένο τύπο backup το λέω για να μην υπάρχει κάποια παρεξήγηση. Έστω αυτός που σχεδίασε την βάση αποφάσισε να βάλει τους πίνακες που δέχονται τα transactions πχ τιμολόγια, κινήσεις λογιστηρίου στο 2ο data file και όλους τους άλλους στο 1ο data file. Επίσης αυτή η βάση είναι τεράστια και ο χρόνος που χρειάζεται να την πάρεις full backup είναι 10 ώρες (υπερβολικό μεν αλλά το έχω δει σε βάση που είναι κάτι ΤΒ). Σε αυτή την περίπτωση μπορεί να παίρνεις full backup κάθε Κυριακή και κάθε μέρα στις 05:00 κάνεις bakup μόνο το 2ο data file το οποίο περιέχει τις κινήσεις.
    Τώρα κάποιος θα μου πει και το filegroup; Δεν ξέρω αν γνωρίζεται τι είναι το filegroup. Μπορείτε να κοιτάξετε στα BOL του SQL Server αν δεν το ξέρετε, απλά εγώ εδώ θα σας πω ότι είναι λογικές οντότητες μέσα στης οποίες ανήκουν τα data files μιας βάσης. Κάθε filegroup ανήκει σε μια συγκέκριμένη βάση και μπορεί να έχει μέσα του περισσότερα από ένα data files. By default κάθε βάση έχει το primary filegroup στο οποίο ανήκει by default το πρώτο data file της βάσης (.mdf). Εάν στο παραπάνω παράδειγμα αντικαταστήσουμε τα files με filegroup θα έχουμε το ίδιο ακριβώς αποτέλεσμα του backup.
    ΠΡΟΣΟΧΗ ΠΡΟΣΟΧΗ ΠΡΟΣΟΧΗ: ΜΕΤΑ ΑΠΟ ΚΑΘΕ FILE/FILEGROUP BACKUP ΠΑΙΡΝΟΥΜΕ Τ-LOG BACKUP. AYTO EINAI ΑΠΑΡΑΒΑΤΟΣ ΚΑΝΟΝΑΣ. Παίζει με Full & Bulk-Logged Recovery Model.
    Partial Backup
    Στην ουσία είναι το backup κάποιου ή κάποιον filegroup(s). Στο παράδειγμα που σας έδωσα στο file/filegroup backup ας έρθουμε να προσθέσουμε ακόμα ένα data file το οποίο θα ανήκει σε ένα ακόμα filegroup. Έτσι η βάση θα έχει τρία (3) data files έστω τα (a1.mdf,a2.ndf,a3.ndf) και έχω και τρία (3) filegroups το primary που έτσι και αλλιώς το έχω και το fg1 και fg2. Στο primary by default ανήκει το πρώτο data file και έχουμε a2.ndf->fg1 & a3.ndf->fg2. Στο 3ο data file βάζουμε τα δεδομένα που είναι από κλεισίματα προηγούμενων χρήσεων και τα οποία δεν θέλουμε αν τα αλλάζουν οι χρήστες. Αυτό είναι εύκολο να γίνει διότι μπορώ να κάνω το fg2 read-only. Ένα τώρα θελήσω να πάρω partial backup στην ουσία παίρνω full backup απλά προσδιορίζω αν θέλω να πάρω τα read only ή τα read-write filegroups. Παίζει με Full & Bulk-Logged Recovery Model.
    Copy Only
    Από τον SQL Server 2005 και μετά έχουμε διαθέσιμο τον συγκεκριμένο τύπο και ομολογώ ότι ήταν κάτι το οποίο έλειπε από το εργαλείο. Θα καταφύγω πάλι σε παράδειγμα για την κατανόηση του τύπου αυτού. Έστω ότι σε ημερήσια βάση έχω μια πολιτική για το backup σε μια βάση μου που είναι η εξής:
    · Full Backup στις 05:00 πμ
    · Transaction Log Backup κάθε μια ώρα
    Στις 15:00 έρχεται το αφεντικό και μου λέει "Θέλω να πάρεις την βάση έτσι όπως είναι τώρα και να την βάλει στο laptop μου γιατί θέλω να πάω ένα ταξίδι και θέλω να έχω τα δεδομένα μαζί μου". Στις προηγούμενες εκδόσεις είχα θέμα με τέτοιου είδους ερωτήματα. Εάν για παράδειγμα έκανα το λάθος και έκανα full backup στην ουσία κατέστρεφα την αλληλουχία των t-logs backups από τις 15:00 και μετά, διότι αυτά θα είχαν σαν βάση το full backup που μόλις έκανα. Έτσι στην περίπτωση που θα ήθελα να κάνω restore στην συγκεκριμένη ημέρα δεν θα ξεκίναγα από το full backup που πήρα στις 05:00 αλλά από αυτό που πήρα στις 15:00. Εάν ήθελα να γυρίσω πριν τις 15:00 θα ξεκίναγα από των 05:00, αλλά θα έπρεπε να τα κάνω όλα με την σειρά που τα πήρα και φυσικά θα χρειαζόμουν περισσότερο χρόνο. Βέβαια όλα θα ήταν καλά αν το backup στις 15:00 το κρατούσα στο μέσο που παίρνω τα backups μου. Για σκεφτείτε όμως τι θα γίνει αν μετά από την μεταφορά στο laptop του αφεντικού το έσβηνα; Πολύ απλά αν ήθελα να γυρίσω στην συγκεκριμένη μέρα αυτό θα ήταν εφικτό να γίνει αλλά μέχρι τις 14:00 όπου ήταν τα τελευταίο valid t-log backup.
    To Copy Only αυτό ακριβώς το πρόβλημα λύνει. Μπορείς να πάρεις full backup οποιαδήποτε στιγμή μέσα στην ημέρα θέλεις χωρίς να επηρεάζεις την συνέχεια στην πολιτική του backup που έχεις.
    How To Backup Database
    Αφού είδαμε, και ελπίζω να έγιναν κατανοητοί οι διάφοροι τύποι του backup, είναι η στιγμή να δούμε και πως παίρνουμε backup αυτούς. Για να το κάνουμε αυτό μπορούμε να χρησιμοποιήσουμε το SQL Server Management Studio ή T-SQL. Δεν θα δώσω ιδιαίτερη βάση στο περιβάλλον του SSMS διότι κυρίως το χρησιμοποιούμε για να πάρουμε ad-hoc backups. Το T-SQL είναι αυτό που μας χρειάζεται διότι αφού το δοκιμάσουμε μετά το κάνουμε schedule. Ναι ξέρω τι θα μου πείτε ότι μπορώ να το κάνω schedule και μέσα από τον SSMS (Maintenance Plans, κλπ), δεν θα διαφωνήσω μαζί σας απλά πιστεύω ότι ο καλύτερος τρόπος εκμάθησης είναι με T-SQL.
    Backup Devices
    Πριν αρχίσω να σας δείχνω τους τρόπους και τις εντολές backup, θέλω να σας πω μερικά πράγματα σχετικά με τα backup devices στα οποία μπαίνουν τα backups που παίρνουμε. Αυτά μπορεί να είναι είτε στον σκληρό δίσκο σας είτε σε ταινία, θα πρέπει όμως να γνωρίζεται ότι η συσκευή της ταινίας πρέπει να είναι φυσικά συνδεδεμένη στη μηχανή στην οποία έχετε βάλει τον SQL Server. Δεν μπορείς π.χ να πάρεις tape backup σε βάση όταν το tape device είναι συνδεμένο στον domain controler server και έχεις σε άλλο server τον SQL Server. Επίσης για τα disk devices αυτά θα πρέπει να είναι δίσκους που βλέπει φυσικά ο server στον οποίο έχουμε εγκαταστήσει τον SQL Server. Εάν θέλουμε να είναι κάποιος share folder μπορεί να γίνει μόνο με UNC Name και όχι με map drive, και φυσικά το account το οποίο ξεκινάει το sql service να έχει τα απαραίτητα read-write permissions σε αυτό.
    Για να σας κάνω την ζωή ευκολότερη θα σας έλεγα να θεωρήσετε ότι το backup device είναι μια συρταριέρα με πολλά συρτάρια, όπου το κάθε ένα συρτάρι είναι ένα backup που παίρνουμε, οποιουδήποτε τύπου (full, diff, t-log) και από οποιαδήποτε βάση. Το μόνο που θα πρέπει να ξέρω είναι τι έχω σε κάθε συρτάρι, το οποίο φυσικά δεν χρειάζεται να το θυμάμαι μιας υπάρχει τρόπος που θα δούμε παρακάτω πως γίνεται να βρω τι έχω μέσα σε αυτό. Θα σας έδινα όμως μια συμβουλή και αυτή είναι backup device να είναι με backups από μια συγκεκριμένη βάση ώστε να μην χάσετε την μπάλα.
    Υπάρχουν δύο είδη backup devices, τα permanent και τα temporary. Η ουσιαστική διαφορά τους είναι ότι τα permanent τα βλέπεις μέσα από SSMS και μπορείς να τα διαχειριστείς με γραφικό περιβάλλον, ενώ τα temporary μόνο με T-SQL μπορείς να τα διαχειριστείς και φυσικά δεν τα βλέπεις από το SSMS. Υπάρχει ακόμα μία διαφορά σε αυτά και είναι ο τρόπος με τον οποίο δημιουργούνται. Τα permanent δημιουργούνται είτε μέσα από το γραφικό περιβάλλον είτε με T-SQL πριν πάρω κάποιο backup, ενώ τα temporary με την εντολή που θα δώσω για να πάρω backup.
    Για να φτιάξω ένα permanent backup device με το SSMS πάω στο Object Explorer Window > Server Objects > Backup Devices > Right Click > New Backup Device. Στο διάλογο που μας δίνεται δίνουμε το όνομα του device και το destination (disk or tape). Ενώ με T-SQL χρησιμοποιώ την sp_addumpdevice πχ
    EXEC master.dbo.sp_addumpdevice 'disk', 'demodevice', 'C:\....\demodevice.bak'
    GO
    Σημείωση : Μέχρι να βάλω το πρώτο backup στο device αυτό δεν υπάρχει σαν αρχείο στο δίσκο αν είναι τύπου disk.
    Όπως είπα και παραπάνω για να φτιάξω temporary device αυτό γίνεται μόνο με T-SQL και μόνο κατά την στιγμή που πάω να πάρω backup π.χ.
    BACKUP DATABASE demoDB TO DISK='C:\...\tempDevName.bak'
    BACKUP LOG demoDB TO DISK='C:\...\tempDevName.bak'
    BACKUP Statement
    Αντιγραφή από τα SQL Server Books Online.

    Backing Up a Whole Database
    BACKUP DATABASE { database_name | @database_name_var }
    TO [ ,...n ]
    [ ] [ next-mirror-to ]
    [ WITH { DIFFERENTIAL | [ ,...n ] } ]
    [;]
    Backing Up Specific Files or Filegroups
    BACKUP DATABASE { database_name | @database_name_var }
    [ ,...n ]
    TO [ ,...n ]
    [ ] [ next-mirror-to ]
    [ WITH { DIFFERENTIAL | [ ,...n ] } ]
    [;]
    Creating a Partial Backup
    BACKUP DATABASE { database_name | @database_name_var }
    READ_WRITE_FILEGROUPS [ , [ ,...n ] ]
    TO [ ,...n ]
    [ ] [ next-mirror-to ]
    [ WITH { DIFFERENTIAL | [ ,...n ] } ]
    [;]

    Backing Up the Transaction Log (full and bulk-logged recovery models)
    BACKUP LOG { database_name | @database_name_var }
    TO [ ,...n ]
    [ ] [ next-mirror-to ]
    [ WITH { | } [ ,...n ] ]
    [;]
    ::=
    {
    { logical_device_name | @logical_device_name_var }
    | { DISK | TAPE } =
    { 'physical_device_name' | @physical_device_name_var }
    }
    ::=
    MIRROR TO [ ,...n ]
    ::=
    {
    FILE = { logical_file_name | @logical_file_name_var }
    | FILEGROUP = { logical_filegroup_name | @logical_filegroup_name_var }
    }
    ::=
    FILEGROUP = { logical_filegroup_name | @logical_filegroup_name_var }
    [ ,...n ]::=
    --Backup Set Options
    COPY_ONLY
    | { COMPRESSION | NO_COMPRESSION }
    | DESCRIPTION = { 'text' | @text_variable }
    | NAME = { backup_set_name | @backup_set_name_var }
    | PASSWORD = { password | @password_variable }
    | { EXPIREDATE = { 'date' | @date_var }
    | RETAINDAYS = { days | @days_var } }
    --Media Set Options
    { NOINIT | INIT }
    | { NOSKIP | SKIP }
    | { NOFORMAT | FORMAT }
    | MEDIADESCRIPTION = { 'text' | @text_variable }
    | MEDIANAME = { media_name | @media_name_variable }
    | MEDIAPASSWORD = { mediapassword | @mediapassword_variable }
    | BLOCKSIZE = { blocksize | @blocksize_variable }
    --Data Transfer Options
    BUFFERCOUNT = { buffercount | @buffercount_variable }
    | MAXTRANSFERSIZE = { maxtransfersize | @maxtransfersize_variable }
    --Error Management Options
    { NO_CHECKSUM | CHECKSUM }
    | { STOP_ON_ERROR | CONTINUE_AFTER_ERROR }
    --Compatibility Options
    RESTART
    --Monitoring Options
    STATS [ = percentage ]
    --Tape Options
    { REWIND | NOREWIND }
    | { UNLOAD | NOUNLOAD }
    --Log-specific Options
    { NORECOVERY | STANDBY = undo_file_name }
    | NO_TRUNCATE
    Θα σταθώ όμως σε μερικά options του BACKUP statement
    Mirror Backup - Enterprise Edition Only
    Με το mirror κάνω αυτό που λέει και η λέξη με μια κίνηση έχω δύο devices που περιέχουν το ίδιο backup. Αυτά όμως πρέπει να είναι του ίδιου τύπου πχ disk και όχι το ένα disk και το άλλο tape. Αρκετά χρήσιμο διότι έτσι εξασφαλίζω ότι θα έχω περισσότερη ασφάλεια.
    Compression Backup - Enterprise Edition Only
    Πολλές φορές μέχρι τώρα για να εξοικονομήσουμε χώρο στο δίσκο αφού τελειώναμε με το backup μας κάναμε compress το device. Πλέον αυτό μπορεί να γίνει αυτόματα από τον SQL Server. Υπάρχει ένα πέναλτι σε χρησιμοποιούμενους πόρους από το σύστημα αλλά είναι πολύ λιγότεροι από αυτούς που χρησιμοποιούσα όταν έκανα μόνος τη διαδικασία με εξωτερικά εργαλεία. Γενικά θα πρέπει να δεις αν το πέναλτι που έχεις αξίζει να το έχεις. Με αυτό θέλω να πω ότι πρέπει να δεις το πόσο compression ratio και αυτό μπορείς να το δεις με αυτό το query
    SELECT backup_size/compressed_backup_size FROM msdb.dbo.backupset
    Striped Backups
    Είναι η δυνατότητα να έχω το backup σε περισσότερα από ένα backup device (μέχρι 64). Χρήσιμο σε περιπτώσεις που βλέπω ότι έχω μια διαδικασία backup να παίρνει μεγάλο χρόνο πχ 4 ώρες, με αυτό μειωνεται ο χρονος στο μισό αν χρησιμοποιήσω 2 backup devices. Ακόμα μια χρήση του είναι όταν έχω πρόβλημα χώρου είτε με το δίσκο που είναι το device είτε με το χώρο τoυ tape (αρκεί βέβαια να έχω δύο tape device).
    How To Restore Database
    Η διαδικασία του restore χωρίζεται σε τρεις φάσεις:
    1. Data Copy Phase
    2. Redo Phase
    3. Undo Phase and Recovery
    Copy Data Phase
    Είναι η πρώτη φάση σε κάθε restore που κάνουμε. Σε αυτή την φάση γίνονται copy όλα (data, log, indexes) από τα backup της βάσης στα database files. Με το τέλος της φάσης αυτής όλα τα περιέχομενα της βάσης έχουν γίνει reset στα περιεχόμενα του backup που κάνουμε restore. Αυτό γίνεται με τα full και differential backups.
    Redo Phase
    Σε αυτή την φάση γίνονται apply όλα τα logged transactions στα δεδομένα που έγιναν copy στην προηγούμενη φάση. Αυτό γίνεται κατά τη στιγμή που γίνονται restore τα transactions log backup. Στην ουσία κοιτάζει ποια transactions που τα logs έχουν δεν υπάρχουν μέσα στα data files και τα κάνει apply.
    Undo Phase and Recovery
    Με το τέλος της προηγούμενης φάσης το επόμενο βήμα είναι βρει τα transactions τα οποία δεν έχουν γίνει commit και κάνει rollback ότι έχουν αυτά κάνει με σκοπό να κρατηθεί η ακεραιότητα και συνοχή των δεδομένων. Αυτό γίνεται διαβάζοντας τα transaction logs. Αφού τελειώσει με την διαδικασία Undo το επόμενο βήμα είναι να προχωρήσει στην επόμενη εσωτερική εργασία της φάσης αυτή που είναι το Recovery Process με την οποία φέρνει στη βάση σε κατάσταση λειτουργίας (online).
    Τι σημαίνουν οι φάσεις αυτές για την διαδικασία Restore;
    Ας απαντήσουμε σε αυτό το κρίσιμο ερώτημα με ένα παράδειγμα. Έστω ότι σε ημερήσια βάση έχουμε το εξής σενάριο για το backup στην βάση μας.
    · FULL BACKUP στις 00:00.
    · DIFFERENTIAL BACKUP στις 06:00, 12:00, 18:00
    · TRANSACTION LOG BACUP κάθε μία ώρα στις εναπομείνασες ώρες
    Στη παρακάτω εικόνα βλέπουμε το σενάριο μας.

    Η ώρα είναι 19:30 και η βάση μας σκάει….
    Τι πρέπει να κάνουμε restore και πως;
    1. Προσπαθούμε να πάρουμε tail-log backup. Εάν το καταφέρουμε γυρνάμε ακριβώς στο σημείο της πτώσης 19:30. Αλλιώς αναγκαστικά γυρνάμε στις 19:00.
    2. Κάνουμε restore to full backup που έχουμε πάρει τα μεσάνυκτα αλλά χωρίς να ενεργοποιήσουμε τις φάσεις 2 & 3. Αυτό γίνεται βάζοντας στην εντολή RESTORE DATABASE το option NORECOVERY. Αυτό το κάνουμε διότι έχουμε να κάνουμε restore και άλλα backups που μας χρειάζονται μέχρι να φτάσουμε στο επιθυμητό σημείου που είναι το σημείο της πτώσης μιας το full backup περιέχει την εικόνα της βάσης όπως ήταν τα μεσάνυκτα.
    3. Επειδή στο σενάριο μας έχουμε differential backups το επόμενο βήμα είναι να κάνουμε restore το ποιο πρόσφατο που έχουμε και δεν είναι άλλο από αυτό των 18:00 όπου και αυτό θα γίνει χωρίς να ενεργοποιήσουμε τις φάσεις 2 & 3. (WITH NORECOVERY).
    4. Μετά κάνουμε restore το t-log backup που έχουμε μετά και αυτό είναι των 19:00. Εδώ τώρα υπάρχουν δύο δρόμοι.
    a. Ο πρώτος δρόμος είναι αυτός που έχει προκύψει από την περίπτωση να μην έχουμε στα χέρια μας tail-log backup. Σε αυτή την περίπτωση με το τέλος του restore θέλουμε να ενεργοποιηθούν οι φάσεις 2 & 3 μιας και δεν έχω κάτι άλλο να κάνω restore έτσι επιλέγω αυτό να το κατεβάζω με την επιλογή WITH RECOVERY, οπότε στο τέλος της θα έχω Online την βάση μου, αλλά θα έχω χάσει αυτή την μίση ώρα.
    b. Ο δεύτερος είναι αυτό που έχει προκύψει από τη περίπτωση να έχω tail-log backup στα χέρια μου. Οπότε επειδή έχω να κάνω restore και αυτό, το t-log backup των 19:00 το κάνω restore χωρίς να ενεργοποιήσω τις φάσεις 2 & 3.
    5. Εφόσον έχω tail-log backup, το κάνω restore και επιλέγω να γίνουν οι φάσεις 2 & 3 (WITH RECOVERY).
    Από το παραπάνω παράδειγμα γίνεται κατανοητό ότι υπάρχει ένας βασικός κανόνας ο οποίος λέει: "ΚΑΝΩ RESTORE ΟΛΑ ΤΑ BACKUPS ΠΟΥ ΕΧΩ ΜΕ ΝΟRECOVERY ΕΚΤΟΣ ΤΟΥ ΤΕΛΕΥΤΑΙΟΥ ΠΟΥ ΤΟ ΚΑΝΩ ΜΕ RECOVERY, ΧΩΡΙΣ ΟΜΩΣ ΝΑ ΞΕΧΝΑΩ ΠΡΙΝ ΚΑΝΩ RESTORE NΑ ΠΡΟΣΠΑΘΗΣΩ ΝΑ ΠΑΡΩ TAIL-LOG BACKUP".
    Restore Statement
    Αντιγραφή από τα SQL Server Books Online.
    --To Restore an Entire Database from a Full database backup (a Complete Restore):
    RESTORE DATABASE { database_name | @database_name_var }
    [ FROM [ ,...n ] ]
    [ WITH
    {
    [ RECOVERY | NORECOVERY | STANDBY =
    {standby_file_name | @standby_file_name_var }
    ]
    | , [ ,...n ]
    | ,
    | ,
    | ,
    | ,
    } [ ,...n ]
    ]
    [;]

    --To perform the first step of the initial restore sequence
    -- of a piecemeal restore:
    RESTORE DATABASE { database_name | @database_name_var }
    [ ,...n ]
    [ FROM [ ,...n ] ]
    WITH
    PARTIAL, NORECOVERY
    [ , [ ,...n ]
    | ,
    ] [ ,...n ]
    [;]

    --To Restore Specific Files or Filegroups:
    RESTORE DATABASE { database_name | @database_name_var }
    [ ,...n ]
    [ FROM [ ,...n ] ]
    WITH
    {
    [ RECOVERY | NORECOVERY ]
    [ , [ ,...n ] ]
    } [ ,...n ]
    [;]

    --To Restore Specific Pages:
    RESTORE DATABASE { database_name | @database_name_var }
    PAGE = 'file:page [ ,...n ]'
    [ , ] [ ,...n ]
    [ FROM [ ,...n ] ]
    WITH
    NORECOVERY
    [ , [ ,...n ] ]
    [;]

    --To Restore a Transaction Log:
    RESTORE LOG { database_name | @database_name_var }
    [ [ ,...n ] ]
    [ FROM [ ,...n ] ]
    [ WITH
    {
    [ RECOVERY | NORECOVERY | STANDBY =
    {standby_file_name | @standby_file_name_var }
    ]
    | , [ ,...n ]
    | ,
    | ,
    } [ ,...n ]
    ]
    [;]

    --To Revert a Database to a Database Snapshot:
    RESTORE DATABASE { database_name | @database_name_var }
    FROM DATABASE_SNAPSHOT = database_snapshot_name

    ::=
    {
    { logical_backup_device_name |
    @logical_backup_device_name_var }
    | { DISK | TAPE } = { 'physical_backup_device_name' |
    @physical_backup_device_name_var }
    }
    ::=
    {
    FILE = { logical_file_name_in_backup | @logical_file_name_in_backup_var }
    | FILEGROUP = { logical_filegroup_name | @logical_filegroup_name_var }
    | READ_WRITE_FILEGROUPS
    }

    [ ,...n ]::=
    --Restore Operation Options
    MOVE 'logical_file_name_in_backup' TO 'operating_system_file_name'
    [ ,...n ]
    | REPLACE
    | RESTART
    | RESTRICTED_USER
    --Backup Set Options
    | FILE = { backup_set_file_number | @backup_set_file_number }
    | PASSWORD = { password | @password_variable }
    --Media Set Options
    | MEDIANAME = { media_name | @media_name_variable }
    | MEDIAPASSWORD = { mediapassword | @mediapassword_variable }
    | BLOCKSIZE = { blocksize | @blocksize_variable }
    --Data Transfer Options
    | BUFFERCOUNT = { buffercount | @buffercount_variable }
    | MAXTRANSFERSIZE = { maxtransfersize | @maxtransfersize_variable }
    --Error Management Options
    | { CHECKSUM | NO_CHECKSUM }
    | { STOP_ON_ERROR | CONTINUE_AFTER_ERROR }
    --Monitoring Options
    | STATS [ = percentage ]
    --Tape Options
    | { REWIND | NOREWIND }
    | { UNLOAD | NOUNLOAD }
    ::=
    | KEEP_REPLICATION
    ::=
    | KEEP_CDC
    ::=
    | ENABLE_BROKER
    | ERROR_BROKER_CONVERSATIONS
    | NEW_BROKER
    ::=
    | {
    STOPAT = { 'datetime' | @datetime_var }
    | STOPATMARK = { 'lsn:lsn_number' }
    [ AFTER 'datetime' ]
    | STOPBEFOREMARK = { 'lsn:lsn_number' }
    [ AFTER 'datetime' ]
    }
    ::=
    | {
    STOPAT = { 'datetime' | @datetime_var }
    | STOPATMARK = { 'mark_name' | 'lsn:lsn_number' }
    [ AFTER 'datetime' ]
    | STOPBEFOREMARK = { 'mark_name' | 'lsn:lsn_number' }
    [ AFTER 'datetime' ]
    }
    Παράδειγμα Backup
    Ας πάρουμε για παράδειγμα το τελευταίο μας
    · FULL BACKUP στις 00:00.
    · DIFFERENTIAL BACKUP στις 06:00, 12:00, 18:00
    · TRANSACTION LOG BACUP κάθε μία ώρα στις εναπομείνασες ώρες

    1. Φτιάχνω ένα permanent device
    EXEC sp_addumpdevice 'disk','pdev1','c:\temp\pdev1.bak'
    GO
    2. Παίρνω το Full backup στις 00:00
    BACKUP DATABASE BackupDemoDB
    TO PDEV1
    WITH INIT, STATS
    GO
    3. Για το Differential backup το statement είναι
    BACKUP DATABASE BackupDemoDB
    TO PDEV1
    WITH DIFFERENTIAL, STATS
    GO
    3. Για το transaction log backup το statement είναι
    BACKUP LOG BackupDemoDB
    TO PDEV1
    WITH DIFFERENTIAL, STATS
    GO
    Και όπως είπαμε παραπάνω η βάση μου σκάει στις 19:30
    Παράδειγμα Restore
    1. Πρώτη κίνηση είναι να πάρω tail-log backup
    BACKUP LOG BackupDemoDB
    TO PDEV1
    WITH NO_TRUNCATE, STATS
    GO
    2. H επόμενη κίνηση είναι κάνω restore το full backup που έχω από τις 00:00. όμως όλα τα backups τα έχω στο ίδιο backup device. Έτσι πρέπει να μάθω τι θα επιλέξω μέσα από αυτό. Για αυτό το λόγο εκτελώ το statement
    RESTORE HEADERONLY FROM PDEV1
    Από το αποτέλεσμα που θα δω με ενδιαφέρουν τα πεδία BackupType , Position, και DatabaseName για την περίπτωση που έχω backup από διαφορετικές βάσεις στο ίδιο backup device. Εδώ δεν έχουμε.
    Το πεδίο BackupType δείχνει τον τύπο του backup (1=FULL, 5=DIFFERENTIAL, 2=TRANSACTION LOG) και το πεδίο Position την θέση του. Αν θυμάστε πιο πάνω το παράδειγμα με την συρταριέρα είναι ας πούμε το συρτάρι. Έτσι αφού έχουμε τις απαραίτητες πληροφορίες προχωράμε
    3. Κάνουμε restore to full backup με ΝΟRECOVERY μιας και πρόκειτε να κάνουμε restore και άλλα backups. Αλλά για να το επιλέξουμε από το backup device χρησιμοποιούμε το FILE=? όπου αντικαθηστούμε το ? με το αριθμό του Position που έχουμε βρει από το βήμα 2 και στο οποίο αντιστοιχεί το Full backup (BackupType=1)
    RESTORE DATABASE BackupDemoDB FROM PDEV1 WITH FILE=1, NORECOVERY
    4. Κάνουμε restore το differential backup των 18:00
    RESTORE DATABASE BackupDemoDB FROM PDEV1 WITH FILE=19, NORECOVERY
    5. Κάνουμε restore το t-log backup των 19:00
    α. για την περίπτωση που έχουμε tail-log backup από το βήμα 1
    RESTORE LOG BackupDemoDB FROM PDEV1 WITH FILE=20, NORECOVERY
    β. εάν δεν έχουμε tail-log
    RESTORE LOG BackupDemoDB FROM PDEV1 WITH FILE=20, RECOVERY
    6. Εφόσον έχουμε tail-log
    RESTORE LOG BackupDemoDB FROM PDEV1 WITH FILE=21, RECOVERY
    Επίλογος
    Σε αυτό το άρθρο σκοπός μου ήταν να κάνω μια καλή εισαγωγή σε αρεκτό βάθος όμως για το τι είναι backup & restore στον SQL Server. Δεν ασχολήθηκα με κάποια σενάρια πχ file/filegroup backup, όμως είναι κάτι που θα το κάνω σύντομα.
  15. antonch
    Σήμερα είχα μια ωραία ερώτηση από μια αγαπητή συνάδελφο σχετικά με τον τελεστή LIKE. Η ερώτηση της ήταν:

    «Πως μπορώ να έχω την δυνατότητα με τον τελεστή LIKE να έχω όλα τα records που είναι περασμένα μέσα στην βάση μου σε ένα πίνακα ακόμα και στην περίπτωση που έχουν περαστεί κάποιοι χαρακτήρες με ελληνικά και κάποιοι με αγγλικά;»

    Στην ουσία αυτό που ήθελε ήταν αν έχω ένα πεδίο σε ένα πίνακα μου και έχω περάσει κάποια records που σε αυτό να έχω τις τιμές Antonis, Αντonis, Αntώνης εάν δώσω Antonis ή Αντώνης να μου τα φέρνει όλα.

    Αυτό γίνεται εύκολα αρκεί να χρησιμοποιήσεις για κάθε χαρακτήρα της λέξης που βάζει στο Like το pattern με τις αγκύλες στο οποίο ορίζεις τους χαρακτήρες που θα ψάξεις

    Πχ

    Έστω ότι έχω τον παρακάτω πίνακα
    create table tbLike
    ( id int identity(1,1) primary key,
    memo nvarchar(100))
    Στον οποίο περνάω 2 records
    insert into tbLike values ('λαλα'),('λaλa')
    και θέλω να μου φέρει και τα δύο records to query μου θα πρέπει να είναι το παρακάτω
    select * from tbLike where memo like 'λ[aα]λ[aα]'
    Επειδή αυτό θέλω να κατασκευάζεται αυτόματα τις έφτιαξα μια user define function η οποία παίρνει σαν παράμετρο το input του χρήστη και φτιάχνει το pattern me κάποιες παραδοχές όσον αφορά την αντιστοιχία των ελληνικών και αγγλικών γραμμάτων.

    Αυτή είναι η παρακάτω

    (σημείωση: Έχω προτιμήσει να την γράψω με τον απλούστερο τρόπο ώστε να είναι εύκολα μετατρέψιμη ακόμα και από κάποιον που ξέρει τα βασικά σε Τ-SQL)
    1: create function fnGreekEnglishLikeString(@instring nvarchar(100)) returns nvarchar(100)
    2: as
    3: begin
    4: --abcdefghijklmnopqrstuvwxyz
    5: --αβγδεζηθικλμνξοπρστυφχψω
    6:
    7: declare @rv nvarchar(100)
    8: declare @i int = 1
    9: declare @length int
    10: select @length = len(@instring)
    11: declare @s nvarchar(10)
    12: set @rv=''
    13: while @i
    14: begin
    15: set @s=''
    16: select @s=case
    17: when substring(@instring,@i,1) = 'a' or substring(@instring,@i,1) = 'α' then '[aα]'
    18: when substring(@instring,@i,1) = 'b' or substring(@instring,@i,1) = 'β' then '[bβv]'
    19: --when substring(@instring,@i,1) = 'c' or substring(@instring,@i,1) = '.' then '[bβ]'
    20: when substring(@instring,@i,1) = 'd' or substring(@instring,@i,1) = 'δ' then '[dδ]'
    21: when substring(@instring,@i,1) = 'e' or substring(@instring,@i,1) = 'ε' then '[eε]'
    22: when substring(@instring,@i,1) = 'f' or substring(@instring,@i,1) = 'φ' then '[fφ]'
    23: when substring(@instring,@i,1) = 'g' or substring(@instring,@i,1) = 'γ' then '[gγ]'
    24: when substring(@instring,@i,1) = 'h' or substring(@instring,@i,1) = 'β' then '[hηiι]'
    25: when substring(@instring,@i,1) = 'i' or substring(@instring,@i,1) = 'ι' then '[iιhη]'
    26: --when substring(@instring,@i,1) = 'j' or substring(@instring,@i,1) = 'β' then '[bβ]'
    27: when substring(@instring,@i,1) = 'k' or substring(@instring,@i,1) = 'κ' then '[kκ]'
    28: when substring(@instring,@i,1) = 'l' or substring(@instring,@i,1) = 'λ' then '[lλ]'
    29: when substring(@instring,@i,1) = 'm' or substring(@instring,@i,1) = 'μ' then '[mμ]'
    30: when substring(@instring,@i,1) = 'n' or substring(@instring,@i,1) = 'ν' then '[nν]'
    31: when substring(@instring,@i,1) = 'o' or substring(@instring,@i,1) = 'ο' then '[oοω]'
    32: when substring(@instring,@i,1) = 'p' or substring(@instring,@i,1) = 'π' then '[pπ]'
    33: --when substring(@instring,@i,1) = 'q' or substring(@instring,@i,1) = 'β' then '[bβ]'
    34: when substring(@instring,@i,1) = 'r' or substring(@instring,@i,1) = 'ρ' then '[rρ]'
    35: when substring(@instring,@i,1) = 's' or substring(@instring,@i,1) = 'σ' or substring(@instring,@i,1) = 'ς' then '[sσς]'
    36: when substring(@instring,@i,1) = 't' or substring(@instring,@i,1) = 'τ' then '[tτ]'
    37: when substring(@instring,@i,1) = 'u' or substring(@instring,@i,1) = 'υ' then '[uυy]'
    38: when substring(@instring,@i,1) = 'v' or substring(@instring,@i,1) = 'β' then '[vβb]'
    39: --when substring(@instring,@i,1) = 'w' or substring(@instring,@i,1) = 'β' then '[bβ]'
    40: when substring(@instring,@i,1) = 'x' or substring(@instring,@i,1) = 'χ' then '[xχ]'
    41: when substring(@instring,@i,1) = 'y' or substring(@instring,@i,1) = 'υ' then '[uυy]'
    42: when substring(@instring,@i,1) = 'z' or substring(@instring,@i,1) = 'ζ' then '[zζ]'
    43: else '['+substring(@instring,@i,1)+']'
    44: end
    45: set @rv=@rv+@s
    46: set @i+=1
    47: end
    48: return @rv
    49: end
    50: go
    Εάν κάποιος θέλει να δει το αποτέλεσμα που επιστρέφει η συγκεκριμένη function αρκεί να εκτελέσει το παρακάτω query
    select dbo.fnGreekEnglishLikeString('antonis')
    go
    Εάν τώρα θέλει να το ενσωματώσει στο query του
    select * from tbLike
    where memo like dbo.fnGreekEnglishLikeString('antonis')
    go
    Happy T-SQL Programming
  16. antonch
    Πριν ξεκινήσω να περιγράφω το συγκεκριμένο εργαλείο, οφείλω να καταθέσω την άποψη μου γι’ αυτό. ΕΙΝΑΙ ΚΑΤΑΠΛΗΚΤΙΚΟ!!!.
    Όσοι έχετε ασχοληθεί από παλία με τον SQL Server, προσωπικά ασχολούμαι από την έκδοση 6.0 (1996), θα έχετε παρακολουθήσει την εξέλιξη του συγκεκριμένου εργαλείου. Σε κάθε έκδοση είχαμε κάποιες βελτιώσεις. Όμως στην έκδοση του SQL Server 2008 πιστεύω ότι έχουμε τις περισσότερες αλλά και τις σημαντικότερες βελτιώσεις. Eίναι μια διαφορετική υλοποίηση του εργαλείου που δίνει μια πληρέστερη εικόνα τόσο στον Database Admin όσο και στον Database Developer.
    Ας ξεκινήσω λοιπόν την περιήγηση στο εργαλείο αυτό.
    Πρώτη αλλαγή είναι το πως τον ξεκινάς. Δεν είναι πλεόν στο Management του SSMS (SQL Server Management Studio). Αλλά πρέπει να κάνεις δεξί κλικ στον server στον Object Explorer και να επιλέξεις την επιλογή Activity Monitor από το menu επιλογών.

    Μετά από αυτο θα δούμε το νέο Activity Monitor

    Όπως θα δείτε υπάρχουν τέσσερα γραφήματα τα οποία δείχνουν
    % Processor Time
    Το ποσοστό του χρόνου που έχει διανυθεί και τον οποίο ο επεξεργαστής έχει δαπανήσει για να εκτελέσει non-idle threads για τον SQL Server σε όλες τις CPUs.
    Waiting Tasks
    Ο αριθμός των tasks τα οποία περιμένουν πόρους είτε του επεξεργαστή, είτε για Ι/Ο, είτε για μνήμη.
    Database I/Ο
    Το transfer rate σε MB/Sec για την μεταφορά των δεδομένων είτε από την μνήμη στον δίσκο, είτε από το δίσκο στη μνήμη, είτε από δίσκο σε δίσκο.
    Batch Requests/sec
    Ο αριθμός των batches που έχουν σταλθεί στον SQL Server.
    Ακριβώς κάτω από τα γραφήματα υπάρχουν τέσσερεις λίστες
    Processes


    Εδώ βλέπουμε κάθε connection που έχει γίνει στον SQL Server και τι ακριβώς κάνει. Η λίστα περιέχει τις εξής πληροφορίες


    Session ID

    Ο μοναδικός αριθμός που παίρνει κάθε connection το γνωστό SPID. Αν δείτε δίπλα του μια κλεψύδρα εύκολα θα καταλάβετε ότι κάτι περιμένει ή είναι μπλοκαρισμένο από κάποιο άλλο connection.

    User Process Flag



    Δείχνει τα αν το συγκεκριμένο process είναι internal (τιμή 0) ή user (τιμή 1). By default δείχνει μόνο τα user αλλά μπορείτε να το αλλαξετε πατώντας το drop down που υπάρχει στο header της κολώνας. Υπάρχει και η τιμή All που τα δείχνει όλα.

    Login



    Το login name με το οποίο το συγκεκριμένο process έχει γίνει.

    Database



    Η τρέχουσα database στην οποία το connection είναι συνδεδεμένο.

    Task State



    Δείχνει εάν το process είναι ενεργό ή όχι. Εδώ μπορώ να έχω τις εξής τιμές
    Done: Ολοκλήρωση Pending: Το process περιμένει ένα worker thread Runnable: Κάτι έχει κάνει λίγο πριν αλλά αυτή την στιγμή δεν κάνει τίποτα αλλά είναι ακόμα συνδεδεμένο. Running: Κάτι κάνει αυτή την στιγμή Suspended: Το process αν και έχει δουλειά να κάνει, έχει σταματήσει γιατί κάτι το εμποδίζει να συνεχίσει. Δες το γιατί από την κολώνα Wait Type.
    Σχόλιο: Διευκρίνηση για το αφεντικό, αυτό δεν δείχνει αν χρήστης το φυσικό πρόσωπο δηλαδή κοιμάτε ή όχι πάνω στο πληκτρολόγιο του. Το λέω γιατί κάποιος πελάτης, μου είπε κάτι τέτοιο στο παρελθόν!!!.


    Command



    Δείχνει το command type (πχ SELECT, DBCC, INSERT, AWAITING COMMAND,…) το οποίο εκτελείτε. Προσοχή δεν δείχνει το πραγματικό command. Εαν θέλετε να δείτε το πραγματικό κάντε δεξί κλικ και επιλέξτε Details.

    Application



    Δείχνει την εφαρμογή με την οποία έχει γίνει το connection. Αυτό μπορεί να ορισθεί από τον developer πάνω στο connection string με το keyword Application Name.

    Wait Time (ms)



    Εαν το process είναι bloked δείχνει τον χρόνο που είναι σε αναμονή σε milliseconds αλλιώς δείχνει 0.

    Wait Type



    Δείχνει το event το οποίο περιμένει το process για να συνεχίσει.

    Wait Resource



    Δείχνει το resource το οποίο περιμένει το process να ελευθερώθεί για να συνεχίσει.

    Blocked By



    Δείχνει το SPID (Session ID) το οποίο έχει μπλοκάρει το process αυτό.

    Head Blocker



    Εαν η τιμή είναι 1 αυτό σημαίνει ότι το Session ID που φαίνεται στην Blocked By κολώνα είναι ο επικεφαλής στην αλυσίδα των μπλοκαρισμάτων.

    Memory Use (KB)



    Δείχνει το ποσό της μνήμης η οποία χρησιμοποιείται από το process αυτό.

    Host



    Δείχνει το computer name από όπου έχει γίνει το connection αυτό.

    Workload Group



    Δείχνει το όνομα του Resource Governor workload group για το query αυτό.
    Resource Waits


    Η λίστα αυτή δείχνει πληροφορίες για την αναμονή στα resources και περιλαμβάνει τις εξής πληροφορίες:
    Wait Category

    Είναι οι κατηγορίες που συγκεντρώνονται για τα wait type statistics. Κάτι αντίστοιχο μπορώ να πάρω με την dmv sys.dm_os_wait_stats.
    Wait Time (ms/sec)
    Ο χρόνος wait time σε ms/sec για όλα τα task τα οποία περιμένουν κάποιο ή κάποια resources στην συγκεκριμένη κατηγορία από το τελευταίο update interval.
    Recent Wait Time (ms/sec)
    O σταθμικός μέσος του wait time ms/sec για όλα τα task τα οποία περιμένουν ένα ή περισσότερα resources στην κατηγορία από το τελευταίο update interval.
    Average Waiter Count
    Ο αριθμός των tasks που περιμένουν για κάποιο ή κάποια resources στην συγκεριμένη κατηγορία σε μια δεδομένη στιγμή.
    Cumulative Wait Time (sec)
    Ο συνολικός χρόνος που τα tasks πρέπει να περιμένουν για ένα ή περισσότερα resources στην κατηγορία από τοτε που ξεκίνησε ο SQL Server ή από τότε που εκτελέσθηκε τελευταία φορά ή DBCC SQLPERF.

    Data File I/O


    Η λίστα αυτή δείχνει πληροφορίες για τα database files των databases που υπάρχουν στον SQL Server, και περιέχει τις εξής πληροφορίες:
    Database

    Το όνομα της βάσης. File Name

    Το όνομα (φυσικό) του αρχειου της βάσης. MB/sec Read

    Το τελευταίο read activity, σε megabytes ανά second, για το database file. MB/sec Written

    Το τελευταίο write activity, σε megabytes ανά second, για το database file. Response Time (ms)

    Ο Μ.Ο του response time, σε milliseconds, για το τελευταίο read-and-write activity στο database file.
    Recent Expensive Queries


    Η λίστα αυτή δείχνει πληροφορίες για τα πιό ακριβά σε resources queries τα οποία έχουν τρέξει στον SQL Server τα τελευταία 30 sec.
    H πληροφορία βγαίνει από την ένωση των dmv sys.dm_exec_requests και sys.dm_exec_query_stats και περιλαμβάνει queries τα οποία είναι σε εξέλιξη αλλά και αυτά τα όποία έχουν τελειώσει μέσα στην χρονική περίοδο των 30 sec, και περιλαμβάνει τις εξης πληροφορίες:
    Query

    Το query statement το οποίο γίνεται monitor.
    Executions/min

    Τα executions ανα λεπτό για το query.
    CPU (ms/sec)

    Η χρήση της CPU από το query
    Physical Reads/sec

    Η χρήση ανα second των physical reads από το query.
    Logical Writes/sec

    Η χρήση ανά second των logical writes από το query.
    Logical Reads/sec

    Η χρήση ανά second των logical reads από το query.
    Average Duration (ms)

    Η μέση διάρκεια εκτέλεσης του query σε milliseconds.
    Plan Count

    O αριθμός των cached query plans για αυτό το query. Ένας μεγάλος αριθμός δείχνει ότι χρειάζεται να στρέψουμε την προσοχή μας στο query αυτό.
  17. antonch
    Η Microsoft ανακοίνωσε την έλευση του BPA για τον SQL Server 2008 R2. Στην ανακοίνωση που έβγαλε αναφέρει για αυτό
    BPA is designed to allow Administrators to validate their SQL Server instances against Microsoft established best practices. It includes best practices validations for SQL Server, SQL Replication, Analysis Services, Integration Services, Reporting Services, and Setup. BPA examines your SQL Server instance with roughly 150 validations of system events, login permissions, SQL Metadata settings, error logs, and reports those items that don’t conform to best practices. For each non-compliant error or warning there are detailed descriptions of the best practice and instructions for becoming compliant.
    For more information and to download SQL Server 2008 R2 BPA go here: http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=0fd439d7-4bff-4df7-a52f-9a1be8725591
    Σύντομα θα ακολουθήσει αναλυτικό post μου που θα σας περιγράφω τα του BPA.
    Καλή αρχή να έχουμε μέχρι τις επόμενες διακοπές μας.
  18. antonch
    Πριν από πολλά χρόνια ήταν 1989 ή 1990 χτυπάει το τηλέφωνο στην εταιρεία Χ και από την άλλη γραμμή του σύρματος ακούγεται μια φωνή "Ρε φιλαράκι τι τρώει ο κομπιούτορας;" Η απάντηση του τεχνικού που είχε όρεξη για πλακούλα ήταν "Ρεύμα" και εξαγριωμένος ο πελάτης απαντά "Μη μου κάνεις πλάκα του γράφω Mitsos και μου λεει φιλε νοτ φουντ (file not found)" Αξέχαστες εποχές DOS!
  19. antonch
    Admin σε εταιρεία αγοράζει server με δίσκο 250 GB. (το αφήνω ασχολίαστο)

    Σπάει τον δίσκο σε C: & D:

    Στο C: δίνει χώρο 29,2 GB και όλα τα υπόλοιπα στο D:

    Στήνει Windows 2008 R2 και SQL Server 2008 όλα στο C: !!!

    Kαι τον D: τι τον κάνει?????????????????????

    Τον αφήνει έτσι όπως είναι για να παίρνει τα backups (ωχ παναγιά μου το είπα)

    Υ.Γ Δεν είχε άλλου είδους backup.

    Σε συνέχεια απο το #2

    Στην εταιρεία αυτή έρχεται ένας εξωτερικός συνεργάτης. Βλέπει τη κατάσταση και κατεβάζει πρόταση ότι για τα backups και μόνο πρέπει να αγορασθεί ξεχωριστό storage!!!!
  20. antonch
    Admin σε εταιρεία έχει ένα server στον οποίο έχει στήσει SQL Server. Ο server αυτός είναι για αποκλειστική χρήση του SQL Server, και έχει 12GB RAM.

    O admin αποφάσισε να δώσει τα 6GB από τα 12GB στον SQL Server.

    Σε ερώτηση γιατί το έκανε αυτό μιας και o server θα έχει αποκλειστικά SQL Server έδωσε την παρακάτω απάντηση:

    "Μπορεί κάποιος που είναι στο δύκτιο να θελήσει λίγο περισσότερη μνήμη, να μην έχω να του δώσω!" []
  21. antonch
    Σήμερα δεν ξημέρωσε καλά για κάποιον συνάδελφο.

    Δυστυχώς για αυτόν είχε να αντιμέτωπίσει ένα σοβαρό θέμα μιας και η βάση του ERP του ήταν suspect. Πραγματικά είχα καιρό να ακούσω για κάτι τέτοιο και τις περισσότερες φορές αιτία είναι hard disk failures.

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

    Βέβαια η καλύτερη λύση σε αυτές τις περιπτώσεις είναι να κάνεις restore το backup σου που θα σου εξασφαλίσει ότι δεν θα έχει απώλειες δεδομένων.

    Στην παρακάτω λύση πάμε όταν δεν έχουμε backup. Κάτι το οποίο το θεωρώ αδιανόητο αλλά δυστυχώς ο συνάδελφος δεν είχε backup!

    Κανόνας Απαράβατος

    ΔΕΝ ΚΑΝΟΥΜΕ ΠΟΤΕ DETACH MIA SUSPECT DATABASE

    Από εκεί και μετά εκτελούμε μια μια τις παρακάτω εντολές

    ALTER DATABASE dbname SET EMERGENCY;
    GO
    ALTER DATABASE dbname SET SINGLE_USER;
    GO
    DBCC CHECKDB (dbname, REPAIR_ALLOW_DATA_LOSS) WITH NO_INFOMSGS, ALL_ERRORMSGS;
    GO

    Μετά από την εκτέλεση της τελευταίας εντολής θα έχουμε ένα μεγάλο μύνημα το οποίο θα μας ενημερώσει για πολλά πράγματα και για το τι ακριβώς έχει γίνει και τι ενδεχομένος άλλες ενέργειες θα πρέπει να κάνουμε

    Το μόνο που μας μένει είναι να ξαναφέρουμε την βάση σε χρήση για πολλαπλούς χρήστες
    ALTER DATABASE dbname SET MULTI_USER;
    GO
  22. antonch
    Πότε τελικά λέμε ότι αυτός ο άνδρας είναι φαλακρός;
    Η φαλάκρα είναι κάτι το οποίο σε αρκετούς άνδρες δημιουργεί ψυχολογικά προβλήματα σε άλλους πάλι κανένα, και σε κάποιους άλλους μερικές φορές τους ακουμπάει για κάποια χρονικά διαστήματα αλλά γενικά εχουν συμβιβαστεί μαζί της.
    Πέρα όμως από αυτό το ερώτημα παραμένει. Πότε τελικά κάποιος είναι φαλακρός;
    Αν για παράδειγμα από τα μαλλιά μου βγάλω μια τρίχα είμαι φαλακρός; Η προφανής απάντηση είναι όχι. Αν βγάλω και δεύτερη και τρίτη και τέταρτη αυτό με κάνει φαλακρό; Προφανώς όχι.
    Αν όμως χάσω εκατοντάδες τρίχες αυτό με κάνει φαλακρό; Ποιός μπορεί να το απαντήσει αυτό με σιγουριά.
    Αν συνεχίσω να χάνω εκατοντάδες τρίχες καθημερινά και ένα πρωινό ο γιός μου φωνάξει «Πατέρα είσαι φαλακρός» είμαι τελικά φαλακρός ή έχω αρχίσει να φαλακρένω.
    Υπάρχει τελικά κάτι το οποίο μπορεί να ορίσει το αν είμαι φαλακρός ή όχι;
    Στην φιλοσοφία αυτο είναι το Σόφισμα του σωρείτη το οποίο είναι ένα λογικό παράδοξο που ασχολείται με την ασάφεια των κατηγορημάτων σε μία λογική πρόταση δείχνοντας ότι είναι πιθανό να μην υπάρχει ένα σαφές όριο ανάμεσα σε ένα κατηγόρημα και την άρνησή του.
    Στον προγραμματισμό έχουμε μάθει να λαμβάνουμε αποφάσεις με βάση την δυαδική λογική (if/else). Έχουμε δομήσει το τρόπο σκέψης μας με αυτό το pattern. Οτιδήποτε πέρα από αυτό μας ξενίζει, μας δημιουργεί πρόβλημα, μας ανατρέπει τον τρόπο σκέψης μας.
    Θυμάμαι χαρακτηριστικά το CheckBox Control το οποίο όταν πρωτοβγήκε δημιούργησε θύελα αντιδράσεων και αυτό γιατί είχε τρεις διαφορετικές περιπτώσεις checked/unchecked/indeterminate. Η τελευταία ήταν αυτή που δημιουργούσε το πρόβλημα. Δεν μπορούσαμε να καταλάβουμε το λόγο ύπαρξης της. Τι σημαίνει ούτε ναι ούτε όχι. Ταλαιπώρησε και συνεχίζει να ταλαιπωρεί αρκετό κόσμο της πληροφορικής.
    Το να γράψεις λογισμικό τελικά δεν είναι μια δυαδική λογική ή είναι;
    Η τρίτη επιλογή πρέπει να λαμβάνεται υπόψη ή όχι;
    Ποιος μπορεί να δώσει ασφαλή απάντηση, και μιλάω για μια απάντηση η οποία να είναι αποδεκτή από όλους. (Δύσκολο)
    Προς τους αδερφούς developers
    Την επόμενη φορά που θα γράψετε software μη σκεφτήτε το άλλο το περίεργο.
    Σκεφτήτε με την λογική του if/else αλλά αλλάξτε το στη τελική σας υλοποίηση με τη switch αφήνοντας ένα παράθυρο στην πιθανότητα
    Καλές Διακοπές
  23. antonch
    Εγκαινιάζω ένα νέο tag στο blog μου με το όνομα Margaritaria. Εδώ θα σας γράφω τα ωραία που κατα καιρούς ακούω. Ελπίζω να σας αρέσει η περιόχη αυτή
    ΚΟΛΛΑΕΙ Ο SQL SERVER??
    ΛΥΣΗ
    ΤΟΝ ΒΓΑΖΟΥΜΕ ΑΠΟ ΤΟ DOMAIN ΠΟΥ ΕΤΣΙ ΚΑΙ ΑΛΛΙΩΣ ΚΑΚΟ ΕΙΝΑΙ ΓΙΑΤΙ ΡΙΧΝΕΙ ΤΟ PERFORMANCE
×
×
  • Create New...