Thursday, March 6, 2008

How to manipulate data through time.

Plenty of us are use bit column as piece of information if record is valid or not. But if  you're selecting only valid records, you must filter table with filtering statement like


SELECT 10 Id
FROM SomeTable
WHERE Del=0


or something like that statement. Multiple queries should take disadvantage of getting full scan of table rows, because we couldn't use index on this column. But there should be more disadvantages.

First of them is absence of history related to our data collections. Second one is higher CPU and I/O load during executing this statement compared to filtering columns which should be indexed.

So I decided to choose two columns in my tables to localize records in time. First of them is column with GETDATE() default value (you know it probably :)), "CreateDate" name with nonclustered index applied, ordered in descend order.

A several weeks ago I spoked with one software company owner about NULL values in columns. "Here is no reason to use delegated values instead of NULLs", he said. "When database engine comes with new version, here can be plenty of difficulties with those values.Why you have choosed this kind of mechanism?"

I thought that seeking some column values  with datetime type was faster then seeking columns which has NULL values enabled. Scanning NULLs is slower then filtering specified values as I noticed in my last article. I answered him that database engine always use index scan and never use index seek. "You're wrong", he said. "Server always use index scan."

I talked about it with my boss and he said: "Compare those two mechanisms".
I decided to write testing script. I've created table with primary key (integer type) with identity incrementation and two columns with datatime type. I inserted about 1 million records into it and then I selected all records with specified values, records with null values and then I seeked records in some random interval. Interval is random for every iteration in both test runs. Selecting range over NULL enabled column is more slower, because SARG is not applied and query is much slower.

You can change previous statement to this:

SELECT [some columns]
FROM dbo.Table
WHERE CreateDate <= @ParameterDate AND DeleteDate >= @ParameterDate

to get records which are valid for specified range and query doesn't consume so much server resources.


Here you can download testing script.

Monday, January 21, 2008

To be with NULL or not to be with NULL

using ISNULL and COALESCE  sql functions.



From time to time you probably catch an idea about optimizing performance in your sql queries.
At time I was written this article, I was using  SQL Server 2005.

I had read much articles about optimizing queries in SQL queries. Some authors had wroted, that ISNULL function is better and other had said that COALESCE is faster, because COALESCE function work similar to CASE statement in programming languages.

So I created a small SQL script to measure which method should be faster.

I ran this script on my machine, so results were better for ISNULL function. I thought it's because COALESCE must hold datatype for each tested value.

Please also notice differences between selecting values from NULL-enabled and non NULL enabled columns with the same data types. I think, that querying over not NULL enabled columns should gain some speed.




















FunctionData typeNullValues PresenceMinCPUTimeMaxCPUTimeAvgCPUTimeMin Timelength [ms]Max Timelength [ms]Avg Timelength [ms]
COALESCEintAllColumnsNull13.3314.6614.00388.95597.64493.30
COALESCEintAllThreeNotNull14.0215.7714.90455.90534.09495.00
COALESCEintFirstColumnNull15.0617.9316.50509.25624.54566.90
COALESCEintLastColumnNotNull13.1615.2314.20457.96568.63513.30
COALESCEvarcharAllColumnsNull27.8230.9729.40854.741287.251071.00
COALESCEvarcharAllThreeNotNull29.6532.5431.10972.101301.891137.00
COALESCEvarcharFirstColumnNull33.5039.0936.301075.531567.661321.60
COALESCEvarcharLastColumnNotNull31.3634.0332.701029.251169.941099.60
ISNULLintAllColumnsNull11.1612.4311.80350.55494.64422.60
ISNULLintAllThreeNotNull9.5310.6610.10245.90526.09386.00
ISNULLintFirstColumnNull11.1612.6311.90367.54419.65393.60
ISNULLintLastColumnNotNull11.2813.1112.20367.91463.48415.70
ISNULLvarcharAllColumnsNull24.7926.2025.50825.061103.33964.20
ISNULLvarcharAllThreeNotNull19.6421.7520.70585.75965.64775.70
ISNULLvarcharFirstColumnNull25.3626.8326.10808.47984.52896.50
ISNULLvarcharLastColumnNotNull28.4730.1229.30929.791095.001012.40