Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Query runs slow with date expression, but fast with string literal

I am running a query with below condition in SQL Server 2008.

Where FK.DT = CAST(DATEADD(m, DATEDIFF(m, 0, getdate()), 0) as DATE)  

Query takes forever to run with above condition, but if just say

Where FK.DT = '2013-05-01' 

it runs great in 2 mins. FK.DT key contains values of only starting data of the month.

Any help, I am just clueless why this is happening.

like image 610
user2158642 Avatar asked Aug 14 '13 20:08

user2158642


People also ask

What causes a query to run slow?

Slow queries can mean your database does more work than it needs to, which means it's using more resources than it needs to. When limited resources like CPU or I/O run out, everything can start to slow down. Inefficient use of resources is also a problem when you're not using the resources you have.

Why is my SQL Server query suddenly slow?

Here's one way to track down the cause of the problem: Find out the most expensive queries running in SQL Server, over the period of slowdown. Review the query plan and query execution statistics and wait types for the slowest query. Review the Query History over the period where performance changed.

What slows down a query?

Slow queries are frequently caused by combining two or more large tables together using a JOIN. Review the number of joins in your query, and determine if the query is pulling more information than is actually needed.

Why is MY SQL query taking so long?

They can take time to transform the data, which can really add up if you’re selecting a lot of data. Using functions in a Where clause or Join clause can also slow down your query. For example, if you filter on an uppercase word, then the value in every row needs to be converted to uppercase to do the conversion:

How to improve the performance of a slow SQL query?

However, there are other ways that a user search can be done, using newer specialised technology. These suggestions for improving a slow SQL query can help in most situations. Knowing what your query is trying to do and avoiding some of the common problems that slow down SQL queries is a great way to improve the performance.

Why is my database running so slow?

Let’s take a look. One of the first things to do is to check how busy the database is. If the database is doing a lot of work at the moment, or under a high load, then all queries including yours will run slowly. To check this, here are some queries you can start with (which is much easier than asking all of the developers).

Is hard-wired literal predicate clause slower?

In the following example hard-wired literal predicate clause is slower: In the following example hard-wired literal predicate clause is slower: I get the exact same plan and performance with both queries.


1 Answers

This could work better:

Where FK.DT = cast(getdate() + 1 - datepart(day, getdate()) as date)

Unless you are running with trace flag 4199 on there is a bug that affects the cardinality estimates. At the time of writing

SELECT DATEADD(m, DATEDIFF(m, getdate(), 0), 0), 
       DATEADD(m, DATEDIFF(m, 0, getdate()), 0)

Returns

+-------------------------+-------------------------+
| 1786-06-01 00:00:00.000 | 2013-08-01 00:00:00.000 |
+-------------------------+-------------------------+

The bug is that the predicate in the question uses the first date rather than the second when deriving the cardinality estimates. So for the following setup.

CREATE TABLE FK
(
ID INT IDENTITY PRIMARY KEY,
DT DATE,
Filler CHAR(1000) NULL,
UNIQUE (DT,ID)
)

INSERT INTO FK (DT)
SELECT TOP (1000000) DATEADD(m, DATEDIFF(m, getdate(), 0), 0)
FROM master..spt_values o1, master..spt_values o2
UNION ALL
SELECT               DATEADD(m, DATEDIFF(m, 0, getdate()), 0)

Query 1

SELECT COUNT(Filler)
FROM FK
WHERE FK.DT = CAST(DATEADD(m, DATEDIFF(m, 0, getdate()), 0) AS DATE)  

Plan 1

Estimates that the number of matching rows will be 100,000. This is the number that match the date '1786-06-01'.

But both of the following queries

SELECT COUNT(Filler)
FROM FK
WHERE FK.DT = CAST(GETDATE() + 1 - DATEPART(DAY, GETDATE()) AS DATE)

SELECT COUNT(Filler)
FROM FK
WHERE FK.DT = CAST(DATEADD(m, DATEDIFF(m, 0, getdate()), 0) AS DATE)  
OPTION (QUERYTRACEON 4199)

Give this plan

Plan 2

Due to the much more accurate cardinality estimates the plan now just does a single index seek rather than a full scan.

like image 117
t-clausen.dk Avatar answered Oct 10 '22 04:10

t-clausen.dk