Friday, December 14, 2012
be wary of the results of sys.dm_db_index_physical_stats
The first query lead the team to believe that index fragmentation was not an issue; the second revealed that this was far from the truth and the crisis was resolved after the massive fragmentation was addressed
Thursday, April 5, 2012
sql server best practices: disk configuration
- store the data and the log on different physical drives
- use the appropriate RAID level depending on the importance of performance and redundancy
- performance only - RAID 0
- redundancy only - RAID 1
- performance and redundancy - RAID 5 or RAID 10
- place files on subsystem connected to different controllers
- mirror the transaction log
- mirror the master and model system databases
- stripe the tempdb database
- store the user database files on a different physical drive from the master , model and tempdb system databases
- monitor the default filegroup or allow for automatic growth
- RAID, SAN and NAS appear as driver letters
- use direct-connected hard drivers or SAN instead of NAS or network file shares
- use NTFS
Wednesday, July 20, 2011
sql server best practices: database creation
Friday, March 11, 2011
sql server best practices: tempdb
- the number of tempdb physical files should be equal to the number of processors or cores on the server. as the name implies, the tempdb stores temporary information required by sql server to complete some operation such as intermediate result sets and temporary tables created in queries. if there is only one tempdb data file, only one processor will be used to read and write information. to make use of all of the available processors, create one physical file per processor and set them all to be the same size.
- since the tempdb is recreated every time the server starts, redundancy is pointless. put the tempdb files on the fastest drives available
- auto-growth of the tempdb is bad for the same reasons that auto-growth is bad for user databases (file fragmentation, processing halts while the file grows, etc.) but, since the tempdb is constantly used for operations, the heinousness of auto-growth of the files grows exponentially with server load. don't be stingy with the default size - allocate enough disk space to ensure that there will always be enough available without depending on growth
- edit: divide the maximum amount of memory allocated to sql server (server properties -> memory) by the number of logical processors to get the recommended size of each tempdb physical file
Wednesday, February 13, 2008
the effects of changing a machine's name on sql server
SELECT @@servername
it will probably return the name of the machine (\instance name) before you renamed it. the fix is this:
sp_dropserver '{oldname}'
where {oldname} is whatever was returned by your first query. after that, run this:
sp_addserver '{newname}(\instancename)', 'LOCAL'
obviously only include (\instancename) if it is a named instance of sql server. restart the sql server service, then re-run your original query and it should return the correct name (you will have to either open a new query editor or re-connect the query editor screen you originally used as restarting the service will cause a disconnect).
Tuesday, February 12, 2008
damned system named constraints
solution: system tables aaaaaaaand ...
dynamic sql!!! weeeeeeeeeeeeeeeee
(i don't know why i got excited about something i genearlly preach against, but, as i've said before, dynamic sql is a necessary evil and can be very useful)
/*1. i think it is good practice to validate that something exists before dropping it (or does not exist before adding it). that way if a sql query that is part of a hotfix is accidentally run more than once, no errors should occur. this script simply checks to see if there is a constraint on a column named 'col_a' in table_a:*/
IF EXISTS (SELECT OBJECT_NAME(constid) FROM sysconstraints CN
INNER JOIN syscolumns CO
ON CN.id = OBJECT_ID('table_a') AND CO.id = CN.id AND
CO.name = 'col_a' AND CN.colid = CO.colorder)
BEGIN
/*2. the following sample then removes the constraint from the column:*/
DECLARE @Sql AS NVARCHAR(2000)
SELECT @Sql = 'ALTER TABLE table_a DROP CONSTRAINT ' + OBJECT_NAME(constid)
FROM sysconstraints CN
INNER JOIN syscolumns CO
ON CN.id = OBJECT_ID('table_a') AND CO.id = CN.id AND
CO.name = 'col_a' AND CN.coldid = CO.colorder
EXEC(@Sql)
END
/* to be extra safe, you may want to include the type of constraint you are dropping as part of the join. the type of constraint is contained in the pseudo-bit-mask value of the sysconstraints 'status' column. as an example, a default constraint will have a status value of '133141' */
Thursday, January 24, 2008
selective filtering, part iii - dynamic sql filtering
if you are using dynamic sql to filter a query based on an optional/nullable parameter, you have to provide something to your WHERE clause in the case that you receive all nulls. here is an example that will not work using the clever ISNULL technique i discussed in my first post:
DECLARE @sSQL nvarchar(4000)
SET @sSQL = 'SELECT col_a FROM table_a '
SET @sSQL = @sSQL + 'WHERE col_b = ''' + ISNULL(@param1, 'col_b') + ''''
exec sp_executesql @sSQL
GO
DECLARE @sSQL nvarchar(4000)
SET @sSQL = 'SELECT col_a FROM table_a '
IF @param1 IS NOT NULL
SET @sSQL = @sSQL + ' WHERE col_b = ''' + @param1 + ''''
exec sp_executesql @sSQL
GO
DECLARE @sSQL nvarchar(4000)
SET @sSQL = 'SELECT col_a FROM table_a '
IF @param1 IS NOT NULL
SET @sSQL = @sSQL + ' WHERE col_b = ''' + @param1 + ''''
IF @param2 IS NOT NULL
SET @sSQL = @sSQL + ' WHERE col_c = ''' + @param2+ ''''
exec sp_executesql @sSQL
GO
DECLARE @sSQL nvarchar(4000)
SET @sSQL = 'SELECT col_a FROM table_a '
SET @sSQL = @sSQL + 'WHERE 1=1 '
IF @param1 IS NOT NULL
SET @sSQL = @sSQL + ' AND col_b = ''' + @param1 + ''''
IF @param2 IS NOT NULL
SET @sSQL = @sSQL + ' AND col_c = ''' + @param2+ ''''
exec sp_executesql @sSQL
GO
now that you've specified a condition that's always true (WHERE 1=1), you can dynamically add additional filters as needed. pretty damn slick if i do say so myself
one last thing - i always declare @sSQL as nvarchar(4000) in my examples because sp_executesql only works with variables with data types of nchar, ntext and nvarchar and the maximum size of an nvarchar variable used with sp_executesql is 4000
selective filtering, part ii - dynamic sql sorting 1
for the uninitiated, dynamic sql is the process of building a query on-the-fly based on parameters passed to the stored procedure. an example of when this is required is if your query accepts the name of a column as a parameter (@param1) and you want to sort your query based on this column/parameter. you can't order a query by a constant, null, or a parameter, even if the parameter evaluates to a valid column name. instead, you write something like this:
DECLARE @sSQL nvarchar(4000)
SET @sSQL = 'SELECT col_a FROM table_a '
IF @param1 IS NOT NULL
SET @sSQL = @sSQL + ' ORDER BY ' + @param1
exec sp_executesql @sSQL
GO
assuming @param1 is a valid column name in table_a, the statement will run and return the values of col_a ordered by the @param1 column (in ascending order by default). notice that i checked to make sure @param1 contained some value since you can't order by null and, if i hadn't checked and @param1 was null, @sSQL would be null (since anyting + null = null). sp_executesql won't throw an error if @sSQL is null; it will just say "Command(s) completed successfully." and return nothing.
that does it for the basics of dynamic sql sorting. the reason i named this post 'dynamic sql sorting 1' is because i can think of at least one more complicated case (e.g. using a case statement to select a column to sort by when another column's value is equal to an input parameter) that i don't want to go into right now since this post is already pretty long. good luck and by all means let me know if you have any comments, corrections or questions. später
Tuesday, January 22, 2008
deadlocks are bad
- process A has a lock on table A and is waiting to update it with information from table B
- process B has a lock on table B and is waiting to update it with information from table A
since neither process will release its lock until the other processes releases its lock, we have ourselves a deadlock. most of the time SQL server "resolves" this issue itself because it has a thread dedicated to its lock manager and someone much smarter than myself came up with an algorithm that allows the lock manager to detect this and kill one of the processes. i have no clue how it chooses which process is the victim of its kill statement, but, from my experience, 99% of the time it is does make this decision and it does kill one of the processes. i've not yet had this happen in SQL 2005, but i can count on one hand the number of times when a deadlock occurred in SQL 2000 and SQL left the decision up to me. in all of these cases, the decision for me was simple - i opened up the SQL activity monitor, scrolled to the right, and saw that a whole bunch of locked processes listed the same process in the 'Blocked By' column. by no means should you be cavalier and just kill this single process before you know what it is, but it's a good place to start. i figured out what the process was and had my client log on to the server hosting the application and simply close it.
back to the other 99% of the time SQL Server resolved the deadlock automagically. this is still very bad. some application was trying to perform some operation on a table or its data and SQL Server flat out squashed it before it could finish. there are certainly ways design a database to minimize the chance of this, but no matter how badass you think your 5NF database is (because there is no way you are badass enough to reach 6NF), you are going to experience a deadlock at some point. i recommend you read the following article to better understand what is going on, and how to track down resolve the problem:
Monday, January 14, 2008
selective filtering, part i
WHERE ...
AND a.column_a = ISNULL(@param1, a.column_a)
a.column_a = a.column_a is always true if a.column_a does not contain nulls, thus if a null is passed to @param1, the statement will not be filtered. if the column can contain nulls, we have to be a be more creative depending on what you want to accomplish. what about using the SET ANSI_NULLS OFF option? this allows for the logical comparison of nulls (i.e. null = null evaluatues to true). doing so makes the example above return all rows when @param1 is null. if you do not want rows returned where a.column_a is null, simply add an additional line:
WHERE ...
AND a.column_a = ISNULL(@param1, a.column_a)
AND a.column_a IS NOT NULL
problem solved. one last thing i should note is my example is likely a much simpler example than what you have since i am only concerned with one column; you must take caution to make sure your other comparisons will not return undesired results when using SET ANSI_NULLS OFF.
