May 27, 2012 at 6:36 pm
I need to create a function for multiple stored procedures so it's easy to manage changes. It's slow. How do you optimize this? :unsure:
CREATE FUNCTION [dbo].[Calc](@Val1 INT, @Val2 INT)
RETURNS INT
AS
BEGIN
DECLARE @VAL3 INT = (SELECT @Val1 * @Val2)
RETURN @VAL3
END
SELECT A.Name,
A.Procedure,
A.Age,
dbo.Calc(A.height, A.weight),
B.Address,
B.City,
B.State,
B.Zip
From Table1 A
INNER JOIN Tanle2 B ON A.ID = B.ID
May 27, 2012 at 7:52 pm
You might try the hint from this article:
My thought question: Have you ever been told that your query runs too fast?
My advice:
INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.
Need to UNPIVOT? Why not CROSS APPLY VALUES instead?[/url]
Since random numbers are too important to be left to chance, let's generate some![/url]
Learn to understand recursive CTEs by example.[/url]
[url url=http://www.sqlservercentral.com/articles/St
May 27, 2012 at 10:04 pm
Hi ReginaR1975
You may follow the suggestions found at the link posted by dwain.c or enable the CLR (Common Language Runtime); the CLR allows you to code functions in Vb.Net or C# (or any other language supported by the Net Framework) and reference them in your T-SQLs.
The steps required to implement your function are:
2. File -> New -> Project
3. Select SQL CLR project (Database Project -> Microsoft SQL Server -> SQL SLR)
4. Click on SQL Server Project
5. Enter a name for your project, I entered SSCfunctions
6. Select the target database to deploy your project; if your database is not on the list, just add it.
7. Answer NO to the prompt if you wish to enable SQL/CLR debugging.
8. Now add an User-Defined Function ... to your project by selecting Project -> Add User-Defined Function at the BIDS IDE (as shown below)
or, you may add it via the Solution Explored; right-click on your project name -> select Add -> select User-Defined Function ...
9. On the Add New Item select the User-Defined Function template and give it a name, like Calc (be sure it ends with .cs if you are using C# or .vb if you are using Vb.Net); then click the Add button.
10. BIDS added the function Calc to the project, into the class UserDefinedFunctions (do not worry about this class name); the default function type is SqlString and it returns a SqlString "Hello"; We will change this function to return an integer and accept two integer parameters.
11. Replace the function type to SqlInt32; add the parameters as shown in the picture; and replace the function's body with the code shown.
12. Now, let's deploy the function, right-click at the project on the Solution Explorer, and select deploy; the image below shows these steps (a) and (b) on the BIDS IDE and the SSMS' database SSIS_PDS_LAB showing its Assemblies node, the new function binary file lands at this node 🙂 Depending on your environment (and permissions) the deployment should take about 30 seconds.
13. Once you deploy your project, SSMS Object explored will show the assembly (named SqlClassLibrary at its Assemblies node) and the function dbo.Calc on the Scalar-valued Functions node in the Programmability-Functions leafs
14. The assembly name is SqlClassLibrary because we did not change it at BIDS, you can change it by selecting the Properties option on the right-click menu of the solution located on the solutions explorer of BIDS
15. It is time to test the new function at SSMS, just open a new query, select the target database, USE SSIS_PDS_LAB (I am sure you will be using a different database); then type the code below:
use SSIS_PDS_LAB
go
select dbo.Calc(4,5) as test
It will fail with an error as shown below; it happens because we haven't enabled CLR, which is the next step.
16. You enable CLR with the following code:
EXEC sp_configure 'show advanced options', 1
RECONFIGURE
EXEC sp_configure 'clr_enabled', 1
RECONFIGURE
EXEC sp_configure 'show advanced options', 0
RECONFIGURE
This is a one-off requirement and your function is ready to rock-n-roll
17. Executing the function 🙂 Now the code shown on the Step 15 should work, the first time it will take time (less than 5 seconds, or probably 10), as SQL is initializing the CLR environment, once it is initilized, future references to the functions will go as very good speed.
18. You can reference the function from other databases as shown in the next query
use SSIS_PDS
go
SELECT ssis_pds_lab.dbo.Calc(4,5) as testing
We prefixed the function with the name of the database containing it.
Hope this helps,
Rock from VbCity
May 27, 2012 at 10:23 pm
Well, not that all that isn't fun, but here's another way to go:
CREATE FUNCTION dbo.itvfCalc(@Val1 INT, @Val2 INT)
RETURNS TABLE As
RETURN SELECT @Val1 * @Val2 As Val3
SELECT A.Name,
A.[Procedure],
A.Age,
(SELECT Val3 FROM dbo.itvfCalc(A.height, A.weight)),
B.Address,
B.City,
B.State,
B.Zip
From Table1 A
INNER JOIN Table2 B ON A.ID = B.ID
I cannot test it of course without your DDL or any test data, but this should address much of your performance issues.
[font="Times New Roman"]-- RBarryYoung[/font], [font="Times New Roman"] (302)375-0451[/font] blog: MovingSQL.com, Twitter: @RBarryYoung[font="Arial Black"]
Proactive Performance Solutions, Inc. [/font][font="Verdana"] "Performance is our middle name."[/font]
May 27, 2012 at 10:37 pm
Just by way of comparision, this query:
SELECT
SUM( dbo.calc(c1.column_id, c2.column_id) / 2 )
FROM sys.system_columns c1
cross join sys.system_columns c2
took 104 seconds to execute on my system.
Whereas this query (another way of doing the same thing as my previous post):
SELECT
SUM( cc.Val3 / 2 )
FROM sys.system_columns c1
cross join sys.system_columns c2
cross apply dbo.itvfCalc(c1.column_id, c2.column_id) cc
took only 3 seconds.
[font="Times New Roman"]-- RBarryYoung[/font], [font="Times New Roman"] (302)375-0451[/font] blog: MovingSQL.com, Twitter: @RBarryYoung[font="Arial Black"]
Proactive Performance Solutions, Inc. [/font][font="Verdana"] "Performance is our middle name."[/font]
May 27, 2012 at 11:03 pm
Rock from VbCity (5/27/2012)
Hi ReginaR1975You may follow the suggestions found at the link posted by dwain.c or enable the CLR (Common Language Runtime); the CLR allows you to code functions in Vb.Net or C# (or any other language supported by the Net Framework) and reference them in your T-SQLs.
Let's see if all of that is actually worth it. Please post the performance for a simple million row test. Of course, you should post the code for the million row test so that others can confirm your findings.
--Jeff Moden
Change is inevitable... Change for the better is not.
May 27, 2012 at 11:08 pm
RBarryYoung (5/27/2012)
Just by way of comparision, this query:
SELECT
SUM( dbo.calc(c1.column_id, c2.column_id) / 2 )
FROM sys.system_columns c1
cross join sys.system_columns c2
took 104 seconds to execute on my system.
Whereas this query (another way of doing the same thing as my previous post):
SELECT
SUM( cc.Val3 / 2 )
FROM sys.system_columns c1
cross join sys.system_columns c2
cross apply dbo.itvfCalc(c1.column_id, c2.column_id) cc
took only 3 seconds.
How many rows do you currently have in sys.system_columns???
--Jeff Moden
Change is inevitable... Change for the better is not.
May 27, 2012 at 11:13 pm
ReginaR1975 (5/27/2012)
I need to create a function for multiple stored procedures so it's easy to manage changes. It's slow. How do you optimize this? :unsure:CREATE FUNCTION [dbo].[Calc](@Val1 INT, @Val2 INT)
RETURNS INT
AS
BEGIN
DECLARE @VAL3 INT = (SELECT @Val1 * @Val2)
RETURN @VAL3
END
SELECT A.Name,
A.Procedure,
A.Age,
dbo.Calc(A.height, A.weight),
B.Address,
B.City,
B.State,
B.Zip
From Table1 A
INNER JOIN Tanle2 B ON A.ID = B.ID
Gosh... I'm thinking that even though that's a scalar UDF, it IS a memory only scalar UDF and there's a pretty good chance that function isn't the main problem.
Take a look at the second link in my signature line below. If you can provide the information outlined in that article the way it's outlined, we stand a much better chance of helping you lick this problem.
--Jeff Moden
Change is inevitable... Change for the better is not.
May 27, 2012 at 11:56 pm
Thanks Jeff
I tried my code with Barry's function getting a result 1 versus 6 seconds in favour of Barry's 🙂 I am in the process of fine-tuning my T-Sql skills so, these threads are helping me to achieve my goals!
Cheers
Hope this helps,
Rock from VbCity
May 28, 2012 at 12:17 am
Jeff Moden (5/27/2012)
How many rows do you currently have in sys.system_columns???
There are 6532 rows in that table in my test database. The scalar T-SQL function :sick: ran for 4 minutes 8 seconds; Barry's in-line TVF version ran for 8 seconds.
Scalar functions (even schema-bound and not accessing data) create a complete new T-SQL context for every execution (every row) and therefore performance sucks horribly. One day, Microsoft will improve the implementation (in-lining simple scalar functions like this) but that is not what we have today. Beware the scalar UDF, whether it accesses data or not.
May 28, 2012 at 12:22 am
Rock from VbCity (5/27/2012)
I tried my code with Barry's function getting a result 1 versus 6 seconds in favour of Barry's.
Which just goes to show how awesome SQLCLR functions are compared with T-SQL scalar functions. However, Barry's example uses a parameterized view (an in-line table-valued function) which is fully in-lined into the calling query before optimization. The overhead of calling a SQLCLR function is very small, but it is not zero. There are cases where SQLCLR functions beat native in-lined T-SQL, but not on such a simple example as this one.
May 28, 2012 at 5:10 am
Jeff Moden (5/27/2012)
RBarryYoung (5/27/2012)
Just by way of comparision, this query:
SELECT
SUM( dbo.calc(c1.column_id, c2.column_id) / 2 )
FROM sys.system_columns c1
cross join sys.system_columns c2
took 104 seconds to execute on my system.
Whereas this query (another way of doing the same thing as my previous post):
SELECT
SUM( cc.Val3 / 2 )
FROM sys.system_columns c1
cross join sys.system_columns c2
cross apply dbo.itvfCalc(c1.column_id, c2.column_id) cc
took only 3 seconds.
How many rows do you currently have in sys.system_columns???
4,666 (SQL Server 2008 R2). Squared, that's 21,771,556.
[font="Times New Roman"]-- RBarryYoung[/font], [font="Times New Roman"] (302)375-0451[/font] blog: MovingSQL.com, Twitter: @RBarryYoung[font="Arial Black"]
Proactive Performance Solutions, Inc. [/font][font="Verdana"] "Performance is our middle name."[/font]
May 28, 2012 at 5:21 am
Rock from VbCity (5/27/2012)
Thanks JeffI tried my code with Barry's function getting a result 1 versus 6 seconds in favour of Barry's 🙂 I am in the process of fine-tuning my T-Sql skills so, these threads are helping me to achieve my goals!
Cheers
Rock: By the way, that was an awesome post above. I'd strongly encourage you to submit it as an article to Steve Jones (the editor here). Don't be dissuaded by these results, as Paul says, it's hard to beat in-lining for something this simple. There are many calculations only moderately more complex where SQLCLR beats everything else hands-down.
[font="Times New Roman"]-- RBarryYoung[/font], [font="Times New Roman"] (302)375-0451[/font] blog: MovingSQL.com, Twitter: @RBarryYoung[font="Arial Black"]
Proactive Performance Solutions, Inc. [/font][font="Verdana"] "Performance is our middle name."[/font]
May 28, 2012 at 6:28 am
Thanks Barry,
I will find out the structure or format of the site's articles and approach Steve Jones, I am not discourage, actually I went into comparing the four solutions discussed in this topic and the CLR approach got a very good second place, I will write down my findings for future members visiting this topic.
ISSUE
The function listed below was performing very slow:
CREATE FUNCTION [dbo].[Calc](@Val1 INT, @Val2 INT)
RETURNS INT
AS
BEGIN
DECLARE @VAL3 INT = (SELECT @Val1 * @Val2)
RETURN @VAL3
END
when used in a query like this:
SELECT
A.Name
, A.Procedure
, A.Age
, dbo.Calc(A.height, A.weight)
, B.Address
, B.City
, B.State
, B.Zip
From Table1 A
INNER JOIN Tanle2 B ON A.ID = B.ID
We did not have the structure, sample data of the two tables involved: Table1 and Tanle2; We overcome this constraint by using system_columns table.
OPTIONS
We discussed 4 options, e.g.
1. The initial function given by the Original Posted (ReginaR1975)
2. Implement SCHEMABINDING as suggested by dwain.c
3. Implement a CLR as suggested by Rock.
4. Implement an in-line table valued function as suggested by RBarryYoung
SOLUTION
We used the following query to find out the performance of these four options
SELECT
SUM( cc.Val3 / 2 )
FROM sys.system_columns c1
cross join sys.system_columns c2
cross apply dbo.itvfCalc(c1.column_id, c2.column_id) cc
Replacing the function as required.
The result found is shown in the following summary
The in-line table valued function handled the 1.6 billions records in around 1 second, the CLR function took a bit more than 6 seconds while the remaining two approaches took more than 100 seconds!
Cheers,
Hope this helps,
Rock from VbCity
May 28, 2012 at 10:19 am
I have about 1.5 million records in Table2. When should I use in-line table valued function as suggested by RBarryYoung vs CLR as suggested by Rock?
Viewing 15 posts - 1 through 15 (of 40 total)
You must be logged in to reply to this topic. Login to reply