Tuesday, May 15, 2012

Implement Database Objects: Implement data types


(This is part of the Study Guide series, 70-464)

Microsoft’s Measured Skill description: This objective may include but is not limited to: use appropriate data types; develop a CLR data type; understand the difference between @Table and #table; impact of GUID (newid, newsequentialid) on database performance, indexing and privacy; use spatial data; LOB data types; understand when and how to use column store and sparse columns; implicit and explicit conversions, integer math

What I see:
·         develop a CLR data type
·         temp table vs. table var (discussed about here)
·         NEWID() vs. NEWSEQUENTIALID()
·         spatial data
·         LOB data types
·         column store
·         sparse columns
·         implicit/explicit conversions

Develop a CLR data type
                CLR User-Defined Types are created utilizing managed code and registering an assembly within SQL Server.  Then a type can be created based off of an Assembly’s class/struct.  For a full, working example on how to accomplish this, follow the walk-through on BOL for CLR User-Defined Types.  It is worth noting particular security concepts relating to the PERMISSION_SET option (can be SAFE, EXTERNAL_ACCESS, or UNSAFE).

NEWID() vs. NEWSEQUENTIALID()
                These are both functions that generate unique identifiers.  There is a very prominent difference between then though:  NEWID() create a [nonsequential] UID, and NEWSEQUENTIALID() creates a sequential UID.  When creating a key column of a clustered index, it is advantageous for that to be ever-incrementing.  If NEWID() was used for a clustered index key column then there would be page splits upon INSERT statements.  But with NEWSEQUENTIALID(), it acts more like an IDENTITY column; with incrementing values.  See the below example to prove the different natures of these functions.  Notice the identity field order for each resulting SELECT queries.  One of them is random, and the other is in a nice order:

Example
use MeasureMySkills;
go

create table NewIdExample
(
       id int identity(1, 1) not null,
       NewIdVal uniqueidentifier
              default newid()
);
go

insert into NewIdExample
values(default);
go 100

create table NewSequentialIdExample
(
       id int identity(1, 1) not null,
       NewSequentialIdVal uniqueidentifier
              default newsequentialid()
);
go

insert into NewSequentialIdExample
values(default);
go 100

select top 10 *
from NewIdExample
order by NewIdVal;

select top 10 *
from NewSequentialIdExample
order by NewSequentialIdVal;

Spatial data
                See BOL’s reference on Spatial Data for information regarding these types.

LOB data types
                See this description of LOB data types (this is from 2008, but the current ones there are still current).  Also, Kimberly Tripp’s blog post on Understanding LOB Data is a great read.

Column store
                Columnstore indexes are one of the cool new features of SQL Server 2012.  Traditionally, indexes are stored by row.  But columnstore indexes now introduce storing indexed data by column.  This can leverage great performance due to the smaller data (and compressed), as it will be less reads.  There are a lot of caveats to columnstore indexes, though:  First off, you can’t do DML against data that is included in a columnstore index.  The workaround is to drop before the INSERT/UPDATE/DELETE and then recreate.  It seems as though the design around columnstore indexes are moreso meant for data warehousing and fact tables, not so much OLTP systems (yet).  There’s no such thing as key columns with a columnstore index, so there is no 16 column limitation like we are typically used to.  Likewise, you can’t have an INCLUDE clause in the definition.  There are many more gotchas and things to know with columnstore indexes, so look to the reference at the bottom to get a full document.

Example
create columnstore index ICX_Department_Name
on HumanResources.Department(Name);
go

Sparse columns
                Sparse columns are a storage method that SQL Server utilizes to leverage saved storage space.  Typically when a column value is NULL it still takes up space.  But if a significant amount of data for a particular column is NULL, the SPARSE attribute can be used to save space as nothing will be stored when the value is NULL.  Like all things, nothing is free though.  Because of a sparse column, there will be additional overhead when dealing with non-NULL data in a sparse column.

Example
use MeasureMySkills;
go

create table MySparseTable
(
       id int identity(1, 1) not null,
       SomeString nvarchar(128) sparse null
);
go

Implicit/Explicit conversions
                An explicit conversion is evident to all of us, as it can be seen through the query with functions like CAST() and CONVERT().  But implicit conversions happen behind the scenes and can be huge performance issues.  Implicit conversions can be analyzed through execution plan predicates, and can potentially make a query non-SARGable, causing a scan when a seek is expected.

References
·         BOL reference on CREATE TYPE
·         BOL reference on CLR UDTs
·         BOL reference on NEWID()
·         BOL reference on Spatial Data

Version-Controlled Code (GitHub)

If there are any comments, questions, issues, or suggestions please feel free to leave a comment below or email me at sqlsalt@gmail.com.

Monday, May 14, 2012

Implement Database Objects: Maintain indexes


(This is part of the Study Guide series, 70-464)

Microsoft’s Measured Skill description: This objective may include but is not limited to: inspect physical characteristics of indexes and perform index maintenance; identify fragmented indexes; identify unused indexes; implement indexes; defrag/rebuild indexes; set up a maintenance strategy for indexes and statistics; optimize indexes (full, filter index); statistics (full, filter) force or fix queue; when to rebuild vs. reorganize and index; create a tuning and maintenance strategy for proactive operations

What I see:
·         physical index characteristics
·         index maintenance
·         index usage
·         create indexes
·         optimize indexes

Physical index characteristics
                Like any other storage, indexes get fragmented over time due to DML and page splits.  The way to gather this information is through the sys.dm_db_index_physical_stats DMV.  A basic query for these stats would be:

Example
use AdventureWorks2012;
go

declare
       @page_count_min bigint = 1000;

select
       db_name(database_id) as database_name,
       object_name(object_id) as object_name,
       index_id,
       index_type_desc,
       avg_fragmentation_in_percent,
       page_count
from sys.dm_db_index_physical_stats
(
       db_id('AdventureWorks2012'),
       default,
       default,
       default,
       'detailed'
)
where page_count >= @page_count_min
order by avg_fragmentation_in_percent desc;

                Notice the data that this query returns.  The fragmentation, as well as the page count.  It is typically advised to ignore fragmentation on indexes that have a negligible page count (i.e. not such a huge impact from the fragmentation).  I have chosen a minimum of 1000 pages to consider.

Index maintenance
                Index maintenance includes cleaning up fragmented indexes that can be retrieved from the section above.  It’s a rule of thumb that any fragmentation between 5% and 30%, and index should be reorganized.  Greater than 30% should be rebuilt.  Again, this is just a rule of thumb and not to be taken as fact in all scenarios.  If your particular maintenance window is large enough, there’s no reason not to rebuild all fragmented indexes.  Likewise, if you are running Enterprise Edition you have the ability for an ONLINE index rebuild.  There are a lot of caveats to that particular method, but it does solve some index availability issues.

Index Rebuild Example
alter index PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID
on Sales.SalesOrderDetail
rebuild;
go

Index ONLINE Rebuild Example
alter index PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID
on Sales.SalesOrderDetail
rebuild
with
(
       online = on
);
go

Index Reorganize Example
alter index PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID
on Sales.SalesOrderDetail
reorganize;
go

Index usage
                Index usage can be found through querying the sys.dm_db_index_usage_stats DMV.  This DMV contains aggregated statistics of how indexes are utilized.  If an index is not contained in this DMV, it hasn’t been utilized since the last time SQL Server started or DMV stats have been cleared.  Using this DMV with a LEFT/RIGHT OUTER JOIN with the sys.indexes catalog view will yield unused indexes.  The below query shows how to get index usage statistics:

Example
select
       db_name(us.database_id) as database_name,
       object_name(us.object_id) as object_name,
       i.name,
       us.user_seeks,
       us.user_scans,
       us.user_lookups,
       us.user_updates
from sys.dm_db_index_usage_stats us
inner join sys.indexes i
on us.object_id = i.object_id
and us.index_id = i.index_id
where us.database_id = db_id();

Create indexes
                Creating indexes can be a very simple operation, but like many things in SQL Server there is a large list of possible options that can be specified.  A basic CREATE INDEX command is shown below, but reference BOL for the full list of options.

Example
use MeasureMySkills;
go

create clustered index IX_LockedTable_Id
on LockedTable(id)
go

Optimize indexes
                Indexes can be used to greatly optimize code and query performance.  Likewise, too many and useless indexes can cause a serious performance degradation with INSERT/UPDATE/DELETE statements.  But given the correct indexes, they can change a table scan to an index seek minimizing IO, CPU time, and overall duration.  The sys.dm_db_missing_index_* prefixed DMVs can be used as suggestions for indexes that can help.  Like DTA, these should be taken as suggestions not necessarily hard facts.

References
·         BOL reference on ALTER INDEX
·         BOL reference on CREATE INDEX

Version-Controlled Code (GitHub)

If there are any comments, questions, issues, or suggestions please feel free to leave a comment below or email me at sqlsalt@gmail.com.