Sql Server Faq

June 28, 2010

Fragmentation should not be the only factor which decides the Rebuild Index

Filed under: Uncategorized — @ 3:02 pm

Until now I was under the impression that fragmentation in the Index is the only factor which decides whether we should rebuild the index.

 

As a rule of thumb we always recommend that when the avg_fragmentation_in_percent in the view  sys.dm_db_index_physical_stats  is between 5 and 30

We should reorganize the index and when the fragmentation is greater than 30 we should rebuild the index.

(Further reading:  http://technet.microsoft.com/en-us/library/ms189858.aspx)

 

However recently my observation showed me that avg_fragmentation_in_percent is not the only factor which should decide the rebuild the index.

 

The rebuild of the index is also decided by depth of the index and in this blog post I will be talking about the same.

 

We all are aware that Clustered Index Keys should preferably have sequential inserts to avoid fragmentation caused due to page splits. However sequential inserts can have its own problem. One of which is blogged by Amit Banerjee

 

Sequential inserts can lead to logical fragmentation  which is not detected  as physical fragmentation by sys.dm_db_index_physical_stats. Now what do I mean by logical Fragmentation?

 

We all know indexes in sql server are organized as B-tree structure using Balanced Tree Algorithm. However as data gets inserted in the index, the Balanced tree structure is no longer maintained and the B-Tree structure goes out of shape which leads to Logical Fragmentation.

 

So even in sequential inserts as data is inserted into the index the Balanced Tree structure stretches towards right and Node splits occurs which increases the depth of the index.

 

The depth of the index is the maximum distance between the root node and the leaf nodes. In the below case Initially when the index was built the depth of index  the depth of index is 3 however after the node splits the depth of the index increases to 4.

 

 

 

 

 

Practical Example

===============

 

use tempdb

go

create table Indexdepth(a int, b char(8000))

go

 

DECLARE @i int

set @i = 0

while (@i < 10000)

begin

insert into Indexdepth values(@i,‘Indexdepth’)

set @i = @i + 1

end

 

create unique clustered index IDX_CLUSTERED on Indexdepth(a)

 

select * from sys.dm_db_index_physical_stats(DB_ID(‘tempdb’),OBJECT_ID(‘dbo.Indexdepth’),1,1,null)

 

—— Avg_fragmentation_in_percent 0 and index_depth 3

 

–Let us do some sequential inserts on the index

 

DECLARE @i int

set @i = 100

while (@i < 500000)

begin

insert into Indexdepth values(@i,‘Indexdepth’)

set @i = @i + 1

end

 

select * from sys.dm_db_index_physical_stats(DB_ID(‘tempdb’),OBJECT_ID(‘dbo.Indexdepth’),1,1,null)

 

—— Avg_fragmentation_in_percent 0.4375 and index_depth 4 

 

 

So in the above example we observed that after doing around some sequential inserts the fragmentation as reported by sys.dm_db_index_physical_stats is only 0.4% which is good and does not qualify it for the Reindexing as per our rule.

 

However if you observe now the depth of the index has increased from 3 to 4.

 

Now what is the implication of the depth of the index?

 

Depth of the index is nothing but the minimum number of pages read when you perform Clustered Index Seek.  So if the index depth is 4  a clustered index seek operation will need to do 4 logical reads atleast as compared to 3 when the index depth is 3.

 

Again 1 additional logical read is fine so long as the index is not involved in Key Lookup operation which is Nonclustered index seek followed by Clustered index seek. i.e following operation

 

Let’s say  if the Index Seek qualifies 100 rows then for each row we have a clustered index seek. So there will be 100 lookups and for each lookup there may be 1 additional logical read. So in all there might be 100 extra logical reads.

 

In the previous example after the index is rebuild , the index_depth is reduced to 3 again.

 

So to conclude, Indexes should be rebuild not only when there is more than 30% fragmentation but also when the index depth is higher than 3.

 

Not everyone might hit the above issue but I thought I should still share it with the people who are not aware of Importance of index depth

Share/Save/Bookmark

June 20, 2010

Fragmentation on Index in Sql Server

Filed under: Uncategorized — @ 6:40 am

 

Hi All,

It has being quite some time since I added a new post since off late I am not spending much of time on research. But I have started my research again and in this post I will be talking about Fragmentation of Index which occurs due to split of root node of an index.

We all know that in Sql server, Index is organized in the form of B-tree structure wherein the data lies on the leaf level (also called leaf nodes) followed by intermediate node and finally root node at the top.

Indexes are performance boosters for Select queries however the same indexes are overhead for DML operations.  Also as data is inserted/updated and deleted the index tend to get Fragmented.

In Sql Server we have 2 types of Fragmention viz Logical Fragmentation and Extent Fragmentation.

Logical Fragmentation happens when the index goes out of shape i.e Balanced Tree structure is distorted while Extent Fragmentation is caused due to page splits when the new pages are allocated in the new extent which might be different area of the datafile or even different datafile of a filegroup.

Fragmentation is mainly caused due to Page Splits which occurs either at the leaf node or intermediate node or root node. Fragmentation at the leaf nodes can be fixed using reorganize of Index however page splits at intermediate node or root node causes depth of the index to increase which is more detrimental from the point of view performance. Since every access path to the leaf node of index goes through root and intermediate node.

So in the following script I have tried to demo how root node of index splits and in order to fix the fragmentation we have rebuild the index because reorganize of index operate s at leaf level but does not operate at root level and intermediate.

Note: In Sql 2000 fragmentation of the index is monitored using DBCC SHOWCONTIG while starting sql 2005 fragmentation is monitored using a DMV sys.dm_db_index_physical_stats

create table test(a int, b char(3950))
go

–truncate table test

declare @i int
set @i = 0
while @i < 100000
    begin
         
insert into test(a,b) values(@i, ‘test’)
          set @i= @i+1;
end

create clustered index test_idx on test(a)
go

——Find the first root page of the index

select first_page, CONVERT (INT, SUBSTRING (root_page, 4, 1) + SUBSTRING (root_page, 3, 1) + SUBSTRING (root_page, 2, 1) + SUBSTRING (root_page, 1, 1)) AS ‘rootPage’,data_pages from sys.system_internals_allocation_units inner join sys.partitions on container_id = partition_id where object_id = OBJECT_ID(‘test’)

—– See the fragmentation, page count  and index _ depth  on the clustered index  initially

select * from sys.dm_db_index_physical_stats(1,OBJECT_ID(‘test’),1,1,NULL)

 index_type_desc   index_depth index_level avg_fragmentation_in_percent fragment_count       avg_fragment_size_in_pages page_count

 —————— ———– ———– —————————- ——————– ————————– ———

 CLUSTERED INDEX    3           0           0.01                         675                  74.0755555555556           50001   

———- DBCC PAGE on the root page shows that points to 114 intermediate pages

dbcc TRACEON(3604)

DBCC PAGE(1,1,50978,3)      root page giving pointers to next intermediate level

1 root page + 114 intermediate page

FileId PageId      Row    Level  ChildFileId ChildPageId a (key)     UNIQUIFIER (key) KeyHashValue

—— ———– —— —— ———– ———– ———– —————- —————-

1      50978       0      2      1           50976       NULL        NULL             NULL
1      50978       1      2      1           50977       1010        0                NULL
1      50978       2      2      1           50979       2020        0                NULL
1      50978       3      2      1           50980       3030        0                NULL
1      50978       4      2      1           50981       4040        0                NULL
1      50978       5      2      1           50982       5050        0                NULL
1      50978       6      2      1           50983       6060        0                NULL
1      50978       7      2      1           50984       7070        0                NULL
1      50978       8      2      1           50985       8080        0                NULL

—- insert few more rows to introduce fragmentation

declare @i int
declare @j int
set @i = 0
set @j = 4
while @i < 110000

begin
insert into test(a,b) values(4, ‘test’)
set @i= @i+1;
end

—- check fragmentation, page_count and depth of the index again

select * from sys.dm_db_index_physical_stats(1,OBJECT_ID(‘test’),1,1,NULL),index_type_desc   index_depth index_level avg_fragmentation_in_percent fragment_count       avg_fragment_size_in_pages page_count    

—————————– ———– —————————- ——————– ————————– ———

CLUSTERED INDEX   4           0           0.368175124088653            1095                 100.458447488584           111915        

—Depth of the index is now 4

— Letz check the root_page again for the table

select first_page, CONVERT (INT, SUBSTRING (root_page, 4, 1) + SUBSTRING (root_page, 3, 1) + SUBSTRING (root_page, 2, 1) + SUBSTRING (root_page, 1, 1)) AS ‘rootPage’,data_pages from sys.system_internals_allocation_units inner join sys.partitions on container_id = partition_id where object_id = OBJECT_ID(‘test’)

— Root Page is changed since it was split and hence we got new depth in the index. The previous root page is now at Level 2 and new root page at Level 3

DBCC PAGE(1,1,141458,3)      root page giving pointers to next 2 intermediate page which is inturn giving pointers to another pages

156 intermediate pages(Level 1) + 2 intermediate  page (Level 1)+ 1 root page

dbcc ind(master,test,1)

 

PageFID PagePID        IAMFID IAMPID      ObjectID    IndexID  PartitionNumber PartitionID     iam_chain_type PageType IndexLevel NextPageFID NextPagePID PrevPageFID PrevPagePID

——- ———–    —— ———– ———– ———– ————- ——————– ——————-

1          620                  NULL    NULL    1403152044    1          1                      7.20576E+16   In-row data      10            NULL    0          0          0          0
1          42050              1          620      1403152044    1          1                      7.20576E+16   In-row data      2          2            1          141459            0          0
1          141458                        1          620      1403152044    1          1                      7.20576E+16   In-row data      2            3          0          0          0          0
1          141459                        1          620      1403152044    1          1                      7.20576E+16   In-row data      2            2          0          0          1          42050

— Let us observe the changes in Fragmentation after reorganizing the index

ALTER INDEX test_idx On TEST REORGANIZE

— No change observed in depth of the index or Fragmentation percent but only page is reduced in the total page_count

select * from sys.dm_db_index_physical_stats(1,OBJECT_ID(‘test’),1,1,NULL)

 

index_type_desc   index_depth index_level avg_fragmentation_in_percent fragment_count       avg_fragment_size_in_pages page_count  

—————– ———– ———– —————————- ——————– ————————– ————-

CLUSTERED INDEX   4           0           0.322569115570885            378                  296.068783068783           111914      

 

— We checked the root page and number of intermediate pages . Those remain the same.

DBCC PAGE(1,1,141458,3)      root page giving pointers to next 2 intermediate page which is inturn giving pointers to another pages

156 intermediate pages(Level 1) + 2 intermediate  page (Level 1)+ 1 root page

  Let us observe the changes in the Fragmentation after rebuilding the index

ALTER INDEX test_idx ON TEST REBUILD

— The depth of the index is reduced to 3 and Fragmentation on the index is almost reduced to 0

index_type_desc  index_depth index_level avg_fragmentation_in_percent fragment_count       avg_fragment_size_in_pages page_count

—————- ———– ———– —————————- ——————– ————————– ———–

CLUSTERED INDEX  3           0           0.01                         1477                 75.77048070413             111913    

–ROOT PAGE IS NOW CHANGED again to a new value and resides at Level 2 while there are

DBCC PAGE(1,1,156138 ,3)

277 intermediate pages (Level 1) + 1 root pages

 

Hope this clarifies how Fragmentation occurs in sql server!!!

 

 

Regards
Parikshit

Share/Save/Bookmark

May 29, 2010

HIGH CPU on Sql Server running Biztalk instances

 

Recently we encountered a case where in a sql server which was running and hosting Biztalk instances was showing 100% CPU.

 

We started troubleshooting from the SQL end to identify who is major consumer of CPU and following were our observations and findings

 

·         We used the perfmon counter Process  %Processor time and confirmed that sqlservr.exe was the major consumer of the CPU.

·         Since the recommendation for Biztalk server is to have MAXDOP 1 we ruled out parallelism as a cause of HIGH CPU.

·         We checked the perfmon counter Sql Server: SQL Statistics , Batch Requests/sec , Sql Compilations/sec and SQL Recompilations/sec but we could not see any major compilations or recompilations/sec so even that was ruled as a cause of the High CPU

·         Finally we started looking at the queries which are major consumers of CPU. We used the following queries and queried the DMvs sys.dm_exec_requests and sys.dm_exec_query_stats to find the queries consuming high CPU

 

SELECT st.text, r.cpu_time  FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS st
ORDER BY cpu_time DESC

SELECT TOP 5 total_worker_time/execution_count AS [Avg CPU Time],

    SUBSTRING(st.text, (qs.statement_start_offset/2)+1,

        ((CASE qs.statement_end_offset

          WHEN -1 THEN DATALENGTH(st.text)

         ELSE qs.statement_end_offset

         END - qs.statement_start_offset)/2) + 1) AS statement_text

FROM sys.dm_exec_query_stats AS qs

CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
ORDER BY total_worker_time/execution_count DESC;

 

 

·         We found that following two stored procedures were one of the major consumers of CPU resources while all the other queries on the servers were getting blocked and waiting on SOS_SCHEDULER_YIELD

 

MSGBOXPERFCOUNTERS_GETSPOOLSIZE                            11.71%

[DBO].[BTS_DEQUEUEMESSAGES_BIZTALKSERVERISOLATEDHOST]     10.59%

 

 

·         We consulted our Biztalk team and found that the first stored proc is used for performance data collection which is fired every 5 secs while second stored procedure is used to dequeue messages coming from Biztalk

 

·         We further drilled the stored procedure [DBO].[BTS_DEQUEUEMESSAGES_BIZTALKSERVERISOLATEDHOST]  and found it was using a cursor to query table

 [BizTalkServerIsolatedHostQ] which was causing blocking on the server.

 

DECLARE btscurse CURSOR FAST_FORWARD FOR  

SELECT TOP 20 w.uidWorkID, w.uidInstanceID, w.uidMessageID, w.snPartRetrieval,

w.fOrderedDelivery, w.snPriority, w.dtLastTouched, w.nID, i.uidProcessID,

i.uidActivationID, i.nState   FROM [BizTalkServerIsolatedHostQ] AS w

WITH (UPDLOCK ROWLOCK READPAST)   INNER LOOP JOIN Instances AS i

WITH (UPDLOCK ROWLOCK READPAST) ON ( w.uidInstanceID = i.uidInstanceID AND uidAppOwnerID = N‘85459549-B70C-4525-B1E6-72D3C0125E52′) AND ( i.uidProcessID IS NULL OR i.uidProcessID = @uidProcessID ) 

 

 

·         We queried the table BizTalkServerIsolatedHostQ and found that there were 581683 messages which were undelivered which were unusual. SO it indicates some of the Orphaned records might be cached in the table which are zombie

 

·         On further research we found that we might hitting a bug mentioned in the KB articles KB 944426 & 936536 & 941690.

 

 

In order to resolve the issue  we used the following Action Plan

 

·         In order to minimize the SQL CPU usage due to the stored procedure MSGBOXPERFCOUNTERS_GETSPOOLSIZE , we set the following registry key to 30sec   

 

HKLM\Software\Microsoft\BizTalk Server\3.0\MsgBox Performance\ CacheRefreshInterval to 30 seconds

 

IMPORTANT : This resolution contains information about modifying the registry. Before you modify the registry, make sure to back it up and make sure that you understand how to restore the registry if a problem occurs. For information about how to back up, restore, and edit the registry, click the following article number to view the article in the Microsoft Knowledge Base:

256986 Description of the Microsoft Windows Registry

 

·         We terminated the orphan cache and RFR and applied the Hotfix  KB 944426 & 936536 & 941690 to avoid the future occurrence of the issue.

 

 

 

After the above changes the CPU on the sql server was resumed to normal.

Hope this help!!  :)

 

Reference

=========

 

http://msdn.microsoft.com/en-us/library/cc296892(BTS.10).aspx

http://msdn.microsoft.com/en-us/library/cc296811(v=BTS.10).aspx

 

 

Parikshit Savjani
Premier Field Engineer, Microsoft

 

Share/Save/Bookmark

February 11, 2009

SQL SERVER 2005 INSTANCE FAILING TO INSTALL AFTER TRYING TO REINSTALL WITH ERROR 1603

Filed under: Uncategorized — @ 9:13 am

 

Many times we need to reinstall a sql server instance due to number of reason.

Whenever you reinstall the sql server instance the success of the installation of the new sql server instance primarily depends on the whether the previous uninstall of the sql server was clean so that all the registry keys and the related folders are deleted.

If the un-installation is done primarily from GUI and if it is successful we can say that the uninstall was clean, however if you go for manual un-installation you need to ensure that all the related registry keys and folders are deleted. We can refer to the following KB article to manually cleanup the sql server instance

http://support.microsoft.com/kb/290991

However if the previous un-installation was not clean, when trying to reinstall the sql server instance the installation may fail with error 1603.

As we have mentioned in our previous post whenever an setup installation fails we need to first check the Summary.txt to check for the Error Message which caused the failure.

——————————————————————————–
Machine : NODE01
Product : Microsoft SQL Server 2005
Product Version : 9.00.1399.06
Install : Failed
Log File : C:\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup001_NODE01_SQL.log
Error Number : 1603
——————————————————————————–
Machine : NODE02
Product : Microsoft SQL Server 2005
Product Version : 9.00.1399.06
Install : Failed
Log File : \\NODE01\C$\Program Files\Microsoft SQL Server\90\Setup Bootstrap\LOG\Files\SQLSetup001_NODE02_SQL.log
Error Number : 1602
——————————————————————————–

 

We checked the SQLSetup001_NODE01_SQL.log which is mentioned above and looked for “Return Value 3” and reached the following part of the log which leads us to the root cause of the error

 

SQLSetup001_NODE01_SQL.log

=======================

MSI (s) (34:E4) [02:35:53:642]: Doing action: CAResolveInstanceName.68C6D15C_77E0_11D5_8528_00C04F68155C
Action ended 02:35:53: SQLLicensing.D20239D7_E87C_40C9_9837_E70B8D4882C2. Return value 1.
MSI (s) (34:A0) [02:35:53:642]: Invoking remote custom action. DLL: C:\WINDOWS\Installer\MSI32F.tmp, Entrypoint: ResolveInstanceName
Action start 02:35:53: CAResolveInstanceName.68C6D15C_77E0_11D5_8528_00C04F68155C.
FTECa.DLL: INFO: FTE: ResolveInstanceName(), Entering…
FTECa.DLL: INFO: FTE: This is NOT an Exchange Server install…
FTECa.DLL: INFO: ResolveInstanceName: FTEInstName obtained: TMSDERIV_PROD
FTECa.DLL: INFO: ResolveInstanceName: FTERudeInstName obtained: MSSQL.8
FTECa.DLL: INFO: LookupInstanceId: Iterating the key: 1
FTECa.DLL: INFO: LookupInstanceId: Iterating rude name: MSSQL.1
FTECa.DLL: INFO: LookupInstanceId: Iterating the key: 2
FTECa.DLL: INFO: LookupInstanceId: Iterating rude name: MSSQL.2
FTECa.DLL: INFO: LookupInstanceId: Iterating the key: 3
FTECa.DLL: INFO: LookupInstanceId: Iterating rude name: MSSQL.4
FTECa.DLL: INFO: LookupInstanceId: Iterating the key: 4
FTECa.DLL: INFO: LookupInstanceId: Iterating rude name: MSSQL.6
FTECa.DLL: INFO: LookupInstanceId: Iterating the key: 5
FTECa.DLL: ERROR: LookupInstanceId: RegQueryValueEx(RudeName) failed. Err = 2
Action ended 02:35:53: CAResolveInstanceName.68C6D15C_77E0_11D5_8528_00C04F68155C. Return value 3.
Action ended 02:35:53: INSTALL. Return value 3.

From the above error we see that setup is unable to resolve the GUID 68C6D15C_77E0_11D5_8528_00C04F68155C into the sql server instance name and hence the setup was failing with error 1603.

Setup was looking at the registry location HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSFTESQLInstMap to resolve the GUID to the Instance Name.

We checked the registry location HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSFTESQLInstMap and found there was wrong mapping for GUID 68C6D15C_77E0_11D5_8528_00C04F68155C.

 

IMPORTANT : This resolution contains information about modifying the registry. Before you modify the registry, make sure to back it up and make sure that you understand how to restore the registry if a problem occurs. For information about how to back up, restore, and edit the registry, click the following article number to view the article in the Microsoft Knowledge Base:

256986 Description of the Microsoft Windows Registry

 

Resolution
========

So to resolve the issue we renamed the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSFTESQLInstMap  to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSFTESQLInstMap.old  and started the installation and the install ran fine without any errors.

 

Note:

This post should not be treated as the Microsoft’s Recommendation or Resolution to the problem, it is only a workaround which worked in our environment and so we would like to share it.

 cmeb76jvk4



 

 

Development Blog

 

 

Share/Save/Bookmark

January 18, 2009

Queries MAY Appear to RUN SLOW on SQL SERVER COMPACT EDITION v3.1 Database

Filed under: Uncategorized — @ 9:19 am

While running your application on SQL CE v3.1 databases you may observe slowness in the performance of some of the queries especially those which involve querying the primary key.

In Sql server databases when you create a Primary Key on a column of a table, it will automatically create a unique index on the column which prevent duplicate entries to be inserted on the primary key column. This Unique index which is generated by Sql server engine automatically are called as the system generated indexes.

Ideally the statistics should be created automatically on the system generated indexes but we have observed that on SQL CE v3.1 databases statistics are not automatically created on the system generated indexes.

Due to the absence of statistics optimizer may select wrong execution which can ultimately lead to poor performance of the sql queries.

To improve the performance we need to manually create the statistics on system generated indexes using following query

CREATE STATISTICS ON <table-name> WITH FULLSCAN,NORECOMPUTE

FULLSCAN ensure that entire table is scanned to generate the statistics and we have not used any sampling.

NORECOMPUTE is used to indicate that Statistics will be updated manually and should not be triggered automatically by optimizer.

Once the statistics are created we need to manually update the statistics periodically using the following command

UPDATE STATISTICS ON <table-name> WITH FULLSCAN,NORECOMPUTE.

The above issue does not occur in SSCE v3.5 in which the statistics are automatically created on system generated indexes and hence the same query might appear to run fast on SSCE v3.5 while it appears to run slow on SSCE v3.1

If after creating and updating the statistics on the system generated indexes manually you still observe slowness in performance you might considering using other query tuning option

 

 

 

 

Share/Save/Bookmark

Newer Posts »

Powered by WordPress