May 27, 2010 at 9:27 am
This is my function (actually, any function gives the slow-down effect):
CREATE FUNCTION [dbo].[fn_sh_fixdate] (@pInputDate DATETIME)
RETURNS DATETIME
BEGIN
RETURN CAST(CONVERT (VARCHAR, DATEADD(hh,3,@pInputDate), 112) AS DATETIME)
END
This is my DB: http://www.sendspace.com/file/zd9xnd (4,6MB zipped backup)
These are my selects (i've bolded the parts that are different. Other parts of selects are identical):
Slow select (takes ~12mins to execute):
SELECT dbo.fn_sh_fixdate(t.datetime1), CAST(kt.sql_variant1 AS NVARCHAR(255)),
CAST(kt.sql_variant1 AS NVARCHAR(255)),
kt.nvarchar9, f.nvarchar3, p.nvarchar3, ep.nvarchar4, t.float1
FROM imp.sh_alluserdata t
INNER JOIN imp.sh_alluserdata kt ON kt.tp_dirname = 'Lists/Katilai' AND t.int6 = kt.tp_id AND t.tp_iscurrent = kt.tp_iscurrent AND t.tp_deletetransactionid = kt.tp_deletetransactionid
INNER JOIN imp.sh_alluserdata f ON f.tp_dirname = 'Lists/Kuras' AND t.int3 = f.tp_id AND t.tp_iscurrent = f.tp_iscurrent AND t.tp_deletetransactionid = f.tp_deletetransactionid
INNER JOIN imp.sh_alluserdata p ON p.tp_dirname = 'Lists/Teral_tipai' AND t.int4 = p.tp_id AND t.tp_iscurrent = p.tp_iscurrent AND t.tp_deletetransactionid = p.tp_deletetransactionid
INNER JOIN imp.sh_alluserdata ep ON ep.tp_dirname = 'Lists/Emisij parametrai' AND t.int7 = ep.tp_id AND t.tp_iscurrent = ep.tp_iscurrent AND t.tp_deletetransactionid = ep.tp_deletetransactionid
WHERE t.tp_dirname = 'Lists/APLEmisij skaiiavimaspastovs parametrai'
AND t.tp_iscurrent = 1 --naujausia versija
AND t.tp_deletetransactionid = 0; --neistrintas
Fast select (takes ~3 seconds):
SELECT CAST(CONVERT (VARCHAR, DATEADD(hh,3,t.datetime1), 112) AS DATETIME), CAST(kt.sql_variant1 AS NVARCHAR(255)),
kt.nvarchar9, f.nvarchar3, p.nvarchar3, ep.nvarchar4, t.float1
FROM imp.sh_alluserdata t
INNER JOIN imp.sh_alluserdata kt ON kt.tp_dirname = 'Lists/Katilai' AND t.int6 = kt.tp_id AND t.tp_iscurrent = kt.tp_iscurrent AND t.tp_deletetransactionid = kt.tp_deletetransactionid
INNER JOIN imp.sh_alluserdata f ON f.tp_dirname = 'Lists/Kuras' AND t.int3 = f.tp_id AND t.tp_iscurrent = f.tp_iscurrent AND t.tp_deletetransactionid = f.tp_deletetransactionid
INNER JOIN imp.sh_alluserdata p ON p.tp_dirname = 'Lists/Teral_tipai' AND t.int4 = p.tp_id AND t.tp_iscurrent = p.tp_iscurrent AND t.tp_deletetransactionid = p.tp_deletetransactionid
INNER JOIN imp.sh_alluserdata ep ON ep.tp_dirname = 'Lists/Emisij parametrai' AND t.int7 = ep.tp_id AND t.tp_iscurrent = ep.tp_iscurrent AND t.tp_deletetransactionid = ep.tp_deletetransactionid
WHERE t.tp_dirname = 'Lists/APLEmisij skaiiavimaspastovs parametrai'
AND t.tp_iscurrent = 1 --naujausia versija
AND t.tp_deletetransactionid = 0; --neistrintas
Could you help me to find out why scalar function slows down this select?
May 27, 2010 at 10:01 am
ok tomas, a couple of things;
scalar functions can slow things down, as they introduce a hidden cursor/REBAR...million rows=million function calls.
I've changed your function froma scalar(called once per row) to a inline table value function...it should perform much better.
there must be a reason for this:
select CAST(CONVERT (VARCHAR, DATEADD(hh,3,getdate()), 112) AS DATETIME);
so anything from 9pm to midnight gets moved to the next day...that's desired, right?
you are adding three hours, then truncating the time off of the value...to speed that up, we want to avoid converting to varchar and back, so we stay with the same datatype.
CREATE FUNCTION [dbo].[fn_sh_fixdate] (@pInputDate DATETIME)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN (
select DATEADD(dd, DATEDIFF(dd,0,DATEADD(hh,3,@pInputDate)), 0) AS TheDate
)
and the way you call it is slightly different:
SELECT myAlias.TheDate , CAST(kt.sql_variant1 AS NVARCHAR(255)),
CAST(kt.sql_variant1 AS NVARCHAR(255)),
kt.nvarchar9, f.nvarchar3, p.nvarchar3, ep.nvarchar4, t.float1
FROM imp.sh_alluserdata t
INNER JOIN imp.sh_alluserdata kt ON kt.tp_dirname = 'Lists/Katilai' AND t.int6 = kt.tp_id AND t.tp_iscurrent = kt.tp_iscurrent AND t.tp_deletetransactionid = kt.tp_deletetransactionid
INNER JOIN imp.sh_alluserdata f ON f.tp_dirname = 'Lists/Kuras' AND t.int3 = f.tp_id AND t.tp_iscurrent = f.tp_iscurrent AND t.tp_deletetransactionid = f.tp_deletetransactionid
INNER JOIN imp.sh_alluserdata p ON p.tp_dirname = 'Lists/Teral_tipai' AND t.int4 = p.tp_id AND t.tp_iscurrent = p.tp_iscurrent AND t.tp_deletetransactionid = p.tp_deletetransactionid
INNER JOIN imp.sh_alluserdata ep ON ep.tp_dirname = 'Lists/Emisij parametrai' AND t.int7 = ep.tp_id AND t.tp_iscurrent = ep.tp_iscurrent AND t.tp_deletetransactionid = ep.tp_deletetransactionid
CROSS APPLY dbo.fn_sh_fixdate(t.datetime1) myAlias
WHERE t.tp_dirname = 'Lists/APLEmisij skaiiavimaspastovs parametrai'
AND t.tp_iscurrent = 1 --naujausia versija
AND t.tp_deletetransactionid = 0; --neistrintas
Lowell
May 28, 2010 at 12:52 am
Hi,
thank you for a fast reply. Yes, adding 3 hours and moving to next day (then truncating time) is intended result.
I've changed to inline table and everything works fast now. I was never aware that scalar functions have such performance issues, so strange...
Thanks again for helping me out.
Regards,
Tomas
May 28, 2010 at 5:40 am
excelent tomas glad it's working for you;
performance wise, it it the same as the inline calculation you tested against?
Lowell
May 28, 2010 at 1:44 pm
Nice job, Lowell.
--Jeff Moden
Change is inevitable... Change for the better is not.
May 28, 2010 at 1:48 pm
Here is a good blog post (if I do say so myself) regarding performance between inline code, inline TVF's, and scalar functions:
Comparing Hardcoded functions, In-Line TVF's, and Scalar Functions
May 28, 2010 at 1:58 pm
Lynn Pettis (5/28/2010)
Here is a good blog post (if I do say so myself) regarding performance between inline code, inline TVF's, and scalar functions:Comparing Hardcoded functions, In-Line TVF's, and Scalar Functions
Very informative Lynn... thanks!
Wayne
Microsoft Certified Master: SQL Server 2008
Author - SQL Server T-SQL Recipes
May 31, 2010 at 5:31 am
Lowell (5/28/2010)
excelent tomas glad it's working for you;performance wise, it it the same as the inline calculation you tested against?
Hi,
yes, performance is the same (or very close - given my small amounts of data, i did not noticed any difference).
June 1, 2010 at 9:48 am
I am submitting a presentation for PASS this fall titled "Death by UDF". 😎 I will be VERY disappointed if it isn't accepted! I have a TON of examples of the myriad of ways UDFs can cause problems - and it goes well beyond crushing your server from a performance perspective!
Best,
Kevin G. Boles
SQL Server Consultant
SQL MVP 2007-2012
TheSQLGuru on googles mail service
Viewing 9 posts - 1 through 9 (of 9 total)
You must be logged in to reply to this topic. Login to reply