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

    « How to pad positive and negative number with zeroes in SQL Server?Please Mr. DBA, Change default passwords and use strong passwords »
    comments

    Late last night my blackberry went nuts again. Sometimes I like that and sometimes I just want to keep sleeping. I know it may be a little odd to say I like having my database servers page me in the middle of the night, but troubleshooting problems is a major reason I went into the database administration field. Turns out the pages were all about blocking issues. Once I went into the blocks and drilled to batches that were abusing my database server, I found the reason to be a matter of fragmentation on a HEAP table. To date I still don't undertand HEAP tables. Well, I understand them. My point is, why use them? Is it really that hard to design tables so this is prevented? No, it's not. The problem still exists though and I had to fix it and fix it quick. Here is how I did.

    So I have a HEAP table with about 1 million rows in it. The HEAP table is fragmented to around 89% when I checked my fragementation logs and it bothers me to greatly. This bothers me mostly due to the fact this table is read countless times by the ERP system. As much as I want to call the designers of the ERP system up and school them on database design and concepts, we all know how far it will get me. So how I can I fix fragmented tables? Here is how...

    Table name is POP10500. The ERP system is Microsoft Dyanmics Great Plains v9 so any alterations to the table structure will essentially take down the system. That means this is offline or after hours only. That pretty much goes for any tables you decide to do this to no matter how it affects the applications.

    So I see my fragmentation by running the following

    1. SELECT  
    2.     OBJECT_NAME(i.OBJECT_ID) AS TableName,
    3.     i.name AS IndexName,
    4.     indexstats.object_id
    5.     ,indexstats.index_id
    6.     ,index_type_desc
    7.     ,avg_fragmentation_in_percent
    8.     ,page_count
    9.     ,record_count
    10.     ,fill_factor
    11. FROM    
    12. sys.dm_db_index_physical_stats(DB_ID('DBA05'), NULL, NULL, NULL, 'DETAILED') indexstats
    13. INNER JOIN sys.indexes i ON i.OBJECT_ID = indexstats.OBJECT_ID
    14. AND i.index_id = indexstats.index_id
    15. Where OBJECT_NAME(i.OBJECT_ID) = 'POP10500'

    Which shows I'm at 89.41%. No one wants to see that number in the avg_fragmentation_in_percent column.

    I know one key variable to my task of fixing this. The users and system tasks always hit column DEX_ROW_ID. I can create a nonclustered index on DEX_ROW_ID as

    1. CREATE NONCLUSTERED INDEX IX_DEX_ROW_ID
    2.     ON dbo.POP10500(DEX_ROW_ID)
    3.     WITH (FILLFACTOR = 70,
    4.         PAD_INDEX = ON);
    5. GO

    But I also know that DEX_ROW_ID is unique. I can confirm that with

    1. SELECT COUNT(*),DEX_ROW_ID
    2. FROM POP10500
    3. GROUP BY DEX_ROW_ID
    4. HAVING COUNT(*) > 1

    And by determining the use of this table from the ERP documentation. Yes, you should read all the documentation not only for the databases you support, but for the applications you support. DEX_ROW_ID is simply therelational key to the header and detail purchase order tables. This table in question is a transactions tables. So why not kill the fragmentation all together taking advantage of DEX_ROW_ID? let's try...

    1. CREATE UNIQUE CLUSTERED INDEX IX_CLUS ON dbo.POP10500(DEX_ROW_ID);
    2. GO

    Let's check fragmentation now

    1. SELECT  
    2.     OBJECT_NAME(i.OBJECT_ID) AS TableName,
    3.     i.name AS IndexName,
    4.     indexstats.object_id
    5.     ,indexstats.index_id
    6.     ,index_type_desc
    7.     ,avg_fragmentation_in_percent
    8.     ,page_count
    9.     ,record_count
    10.     ,fill_factor
    11. FROM    
    12. sys.dm_db_index_physical_stats(DB_ID('DBA05'), NULL, NULL, NULL, 'DETAILED') indexstats
    13. INNER JOIN sys.indexes i ON i.OBJECT_ID = indexstats.OBJECT_ID
    14. AND i.index_id = indexstats.index_id
    15. Where OBJECT_NAME(i.OBJECT_ID) = 'POP10500'

    0% :) Happy days! Drop the clustered index

    1. DROP INDEX IX_CLUS ON dbo.POP10500
    2. GO

    Here is the thing. Dropping the index will create fragementation. Not much but it will. So check your fragmentation again. Mine goes to around 0.017%. This is much better than 89% of course.

    Now let's say I didn't have DEX_ROW_ID available to use. I can add a unique column to the table
    and cluster it. This will fix the fragmentation. You want to do your best to order the physical
    data the way you want it though. Let's say PONUMBER is the column that is always filtered on.

    1. ALTER TABLE POP10500
    2.     ADD CLUSCOL INT IDENTITY(1,1)
    3. GO
    4. CREATE UNIQUE CLUSTERED INDEX IX_CLUS ON dbo.POP10500(CLUSCOL,PONUMBER);
    5. GO
    6. DROP INDEX IX_CLUS ON dbo.POP10500

    After all is said and done, I grabbed the query that the system was running and causing the blocks. Checked the plan and execution times prior to the de-frag steps. The query ran in around 11 seconds. Horrid!!! After physically ordering the table and removing the fragmentation I was getting sub second execution times. Blocking issues resolved!

    This type of fix isn't the all saving grace for every HEAP table but in many situations it can really increase your performance. It's a great way to move HEAP tables to filegroups around on disk as well to increase performance for these huge and annoying tables :)

    About the Author

    Ted Krueger is a SQL Server MVP and has been working in development and database administration for 13+ years. Specialties range from High Availability and Disaster / Recovery setup and testing methods down to custom assembly development for SQL Server Reporting Services. Ted blogs and is also one of the founders of LessThanDot.com technology community. Some of the articles focused on are Backup / Recovery, Security, SSIS and working on SQL Server and using all of the SQL Server features available to create stable and scalable database services. @onpnt
    Social SitingsTwitterLinkedInLTD RSS Feed
    1535 views
    Instapaper

    1 comment

    Comment from: SQLDenis [Member] Email
    *****
    SQLDenis I helped people with deadlocks many times when I asked them to check fragmentation levels...after rebuild or defrag/reorganization the deadlocks also vanished


    04/24/09 @ 07:35

    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.)