Login or Sign Up to become a member!
LessThanDot Sit Logo

LessThanDot

Data Management

Less Than Dot is a community of passionate IT professionals and enthusiasts dedicated to sharing technical knowledge, experience, and assistance. Inside you will find reference materials, interesting technical discussions, and expert tips and commentary. Once you register for an account you will have immediate access to the forums and all past articles and commentaries.

LTD Social Sitings

Lessthandot twitter Lessthandot Linkedin Lessthandot friendfeed Lessthandot facebook Lessthandot rss

Note: Watch for social icons on posts by your favorite authors to follow their postings on these and other social sites.

Your profile

    Search

    XML Feeds

    Google Ads

    « SQL Server Database Administration Tip a Day SeriesPresenting for PASSMN May 17th »
    comments

    Here is a quick demonstration that shows you what can happen when you use defaults that are much shorter than the value that is updated from an insert trigger. The ModifiedBy column has a default of '' but in the trigger it gets updated to 'SomeapplicationName used by ' +SUSER_NAME(). Ideally you want the default to also be 'SomeapplicationName used by ' +SUSER_NAME()

    Let's take a look, first create the following table

    1. CREATE TABLE TestFrag (
    2.     id INT NOT NULL IDENTITY PRIMARY KEY,
    3.     SomeData UNIQUEIDENTIFIER DEFAULT newsequentialid(),
    4.     Somedate datetime DEFAULT GETDATE(),
    5.     SomeOtherData CHAR(200) DEFAULT 'bla',
    6.     ModifiedBy varchar(100) DEFAULT '')

    Add a trigger on that table

    1. CREATE TRIGGER [dbo].[Tr_TestFrag] ON [dbo].[TestFrag] FOR Insert
    2. AS
    3. UPDATE t
    4.         SET    ModifiedBy = 'SomeapplicationName used by ' +SUSER_NAME()
    5.         FROM   TestFrag t
    6.         JOIN inserted i ON t.id = i.id
    7.        
    8. GO

    Now add another identical table, the only difference is that the default matches what gets updated from within the trigger

    1. CREATE TABLE TestFrag2 (
    2.     id INT NOT NULL IDENTITY PRIMARY KEY,
    3.     SomeData UNIQUEIDENTIFIER DEFAULT newsequentialid(),
    4.     Somedate datetime DEFAULT GETDATE(),
    5.     SomeOtherData CHAR(200) DEFAULT 'bla',
    6.     ModifiedBy varchar(100) DEFAULT 'SomeapplicationName used by ' +SUSER_NAME())

    Here is the other trigger

    1. CREATE TRIGGER [dbo].[Tr_TestFrag2] ON [dbo].[TestFrag2] FOR Insert
    2. AS
    3. UPDATE t
    4.         SET    ModifiedBy = 'SomeapplicationName used by ' +SUSER_NAME()
    5.         FROM   TestFrag2 t
    6.         JOIN inserted i ON t.id = i.id
    7.        
    8. GO

    Now let's pump 100000 rows into both tables

    1. INSERT TestFrag(Somedate)
    2. SELECT TOP 100000 GETDATE()
    3. FROM sysobjects s1
    4. CROSS JOIN sysobjects s2
    5. CROSS JOIN sysobjects s3
    1. INSERT TestFrag2(Somedate)
    2. SELECT TOP 100000 GETDATE()
    3. FROM sysobjects s1
    4. CROSS JOIN sysobjects s2
    5. CROSS JOIN sysobjects s3

    Run this to just verify that we have the same data

    1. SELECT TOP 10 * FROM TestFrag
    2. SELECT TOP 10 * FROM TestFrag2


    Now let's look how much space each table is using

    1. EXEC sp_spaceused 'TestFrag'
    2. EXEC sp_spaceused 'TestFrag2'


    name		rows		reserved	data		index_size	unused
    TestFrag	100000     	47240 KB	47064 KB	104 KB		72 KB
    TestFrag2	100000     	28744 KB	28576 KB	112 KB		56 KB



    See that, the table with the same default as in the trigger is using a lot less data?

    Now let's see how bad the fragmentation is. Here is the 2005 and up version

    1. SELECT  
    2.     OBJECT_NAME(i.OBJECT_ID) AS TableName
    3.     ,indexstats.index_id
    4.     ,index_type_desc
    5.     ,avg_fragmentation_in_percent
    6.     ,page_count
    7.     ,record_count
    8.     ,fill_factor
    9. FROM    
    10. sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'DETAILED') indexstats
    11. INNER JOIN sys.indexes i ON i.OBJECT_ID = indexstats.OBJECT_ID
    12. AND i.index_id = indexstats.index_id
    13. WHERE OBJECT_NAME(i.OBJECT_ID) in ('TestFrag','TestFrag2')


    TableName index_id index_type_desc avg_fragmentation_in_percent page_count record_count fill_factor
    TestFrag1CLUSTERED INDEX99.422063573007 5883 100000 0
    TestFrag1CLUSTERED INDEX0 11 5883 0
    TestFrag1CLUSTERED INDEX0 1 11 0
    TestFrag21CLUSTERED INDEX0.335946248600224 3572 100000 0
    TestFrag21CLUSTERED INDEX0 12 3572 0
    TestFrag21CLUSTERED INDEX0 1 12 0

    Yikes, do you see that, one table is completely fragmented.

    Here is the 2000 version by using showcontig

    DBCC SHOWCONTIG scanning 'TestFrag' table...
    Table: 'TestFrag' (933578364); index ID: 1, database ID: 14
    TABLE level scan performed.
    - Pages Scanned................................: 5883
    - Extents Scanned..............................: 738
    - Extent Switches..............................: 5879
    - Avg. Pages per Extent........................: 8.0
    - Scan Density [Best Count:Actual Count].......: 12.52% [736:5880]
    - Logical Scan Fragmentation ..................: 99.42%
    - Extent Scan Fragmentation ...................: 0.27%
    - Avg. Bytes Free per Page.....................: 3234.5
    - Avg. Page Density (full).....................: 60.04%
    DBCC execution completed. If DBCC printed error messages, contact your system administrator.
    
    
    DBCC SHOWCONTIG scanning 'TestFrag2' table...
    Table: 'TestFrag2' (1205579333); index ID: 1, database ID: 14
    TABLE level scan performed.
    - Pages Scanned................................: 3572
    - Extents Scanned..............................: 450
    - Extent Switches..............................: 449
    - Avg. Pages per Extent........................: 7.9
    - Scan Density [Best Count:Actual Count].......: 99.33% [447:450]
    - Logical Scan Fragmentation ..................: 0.34%
    - Extent Scan Fragmentation ...................: 0.44%
    - Avg. Bytes Free per Page.....................: 89.3
    - Avg. Page Density (full).....................: 98.90%
    DBCC execution completed. If DBCC printed error messages, contact your system administrator.
    

    As you can see you will get horrible page splits if your trigger expands the row every time an insert happens.




    *** Remember, if you have a SQL related question, try our Microsoft SQL Server Programming forum or our Microsoft SQL Server Admin forum

    About the Author

    User bio imageDenis has been working with SQL Server since version 6.5. Although he worked as an ASP/JSP/ColdFusion developer before the dot com bust, he has been working exclusively as a database developer/architect since 2002. In addition to English, Denis is also fluent in Croatian and Dutch, but he can curse in many other languages and dialects (just ask the SQL optimizer) He lives in Princeton, NJ with his wife and three kids.
    Social SitingsTwitterFacebookLinkedInHomePageFlickrLTD RSS Feed
    500 views
    Instapaper

    1 comment

    Comment from: David Forck (thirster42) [Member]
    makes perfect sense to me!
    05/06/11 @ 10:10

    Leave a comment


    Your email address will not be revealed on this site.

    Your URL will be displayed.
    (Line breaks become <br />)
    (Name, email & website)
    (Allow users to contact you through a message form (your email will not be revealed.)