May 4, 2009 at 8:42 am
hi everyone, im busy optimizing a stored proc that is the longest running and does the most I/O in from our application. Is there a better way to write this particular case statement?
Select
mc.MovementIdentifierContext,
mc.MovementIdentifier,
mc.MovementIdentifierSequence,
mc.Data,
mc.[XML],
case
when mr.RelationshipIdentifier IN (
select CardIdentifier
from "CardCollection" cc
join "EntityRelationship" er on cc.CardIdentifier = er.RelationshipIdentifier
where er.Relationship = 'Card'
and er.EntityIdentifier IN ( Select er2.EntityIdentifier
from EntityRelationship er2
where er2.Relationship = 'Affiliate'
and er2.RelationshipIdentifier = @ReferrerIdentifier ) )
then 'false' else 'true'
end as AccessDenied
from
"MovementCollection" mc
join "MovementRelationship" mr on mc.MovementIdentifier = mr.MovementIdentifier
May 4, 2009 at 9:19 am
The logic seems a little more complicated than it has to be. I think you can just use LEFT joins in place of your subqueries and simply test values in the CASE statement. To be certain, would you mind posting up some sample schema and data for one false case and one true case? That way you will be certain of getting a tested solution.
Thanks,
Bob
__________________________________________________
Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills
May 6, 2009 at 2:46 am
anyone? 🙁
May 6, 2009 at 3:08 am
Is there a better way to write this particular case statement?
Maybe, perhaps as Bob has suggested using "outer join" and possibly "group by" instead of the sub-query, but you'll need to post table definitions, some sample data with expected results.
____________________________________________________
Deja View - The strange feeling that somewhere, sometime you've optimised this query before
How to get the best help on a forum
http://www.sqlservercentral.com/articles/Best+Practices/61537May 6, 2009 at 3:50 am
Hi,
Try this,
creat the function like this
CREATE FUNCTION TR_FA (@mr_RelationshipIdentifier varchar(10),@ReferrerIdentifier varchar(10))
RETURNS varchar(10)
begin
if @mr_RelationshipIdentifier not in (
select cc.CardIdentifier
from CardCollection cc,
EntityRelationship er,
EntityRelationship er2
where cc.CardIdentifier = er.RelationshipIdentifier
and er.Relationship = 'Card'
and er.EntityIdentifier = er2.EntityIdentifier
and er2.Relationship = 'Affiliate'
and er2.RelationshipIdentifier = @ReferrerIdentifier)
begin
return 'FALES'
end
else 'TRUE'
end
and call this function in the select statement
mc.Data,
mc.[XML],
select * from DB..TR_FA (mr.RelationshipIdentifier,@ReferrerIdentifier )
from
"MovementCollection" mc
ARUN SAS
May 6, 2009 at 4:07 am
Perhaps you can try this one?
WITH AccessDenied( CardIdentifier ) AS
(
SELECT DISTINCT CardIdentifier
FROM
CardCollection AS cc
INNER JOIN
EntityRelationship AS er ON
cc.CardIdentifier = er.RelationshipIdentifier
INNER JOIN
EntityRelationship AS er2 ON
er2.Relationship = 'Affiliate'
AND er2.RelationshipIdentifier = @ReferrerIdentifier
AND er2.EntityIdentifier = er.EntityIdentifier
WHERE er.Relationship = 'Card'
)
SELECT
mc.MovementIdentifierContext
, mc.MovementIdentifier
, mc.MovementIdentifierSequence
, mc.Data
, mc.[XML]
, CASE WHEN ad.CardIdentifier IS NULL THEN 'true' ELSE 'false' END AS AccessDenied
FROM
MovementCollection mc
INNER JOIN
MovementRelationship mr ON
mc.MovementIdentifier = mr.MovementIdentifier
LEFT OUTER JOIN
AccessDenied AS ad ON
ad.CardIdentifier = RelationshipIdentifier
May 6, 2009 at 5:08 am
The fundamental problem with the original query is the JOIN in the subquery. (These always seem to end up as nested loops which is rarely a good idea.)
You should avoid joins in subqueries by either using outer joins or using nested EXISTS or IN subqueries. Here are two more examples:
SELECT
mc.MovementIdentifierContext,
mc.MovementIdentifier,
mc.MovementIdentifierSequence,
mc.Data,
mc.[XML],
CASE
WHEN EXISTS
(
SELECT *
FROM MovementRelationship mr
WHERE mr.MovementIdentifier = mc.MovementIdentifier
AND EXISTS
(
SELECT *
FROM CardCollection cc
WHERE mr.RelationshipIdentifier = cc.CardIdentifier
AND EXISTS
(
SELECT *
FROM EntityRelationship er
WHERE er.RelationshipIdentifier = cc.CardIdentifier
AND er.Relationship = 'Card'
AND EXISTS
(
SELECT *
FROM EntityRelationship er2
WHERE er2.EntityIdentifier = er.EntityIdentifier
AND er2.Relationship = 'Affiliate'
AND er2.RelationshipIdentifier = @ReferrerIdentifier
)
)
)
)
THEN 'false'
ELSE 'true'
END AS AccessDenied
FROM
MovementCollection mc
SELECT
mc.MovementIdentifierContext,
mc.MovementIdentifier,
mc.MovementIdentifierSequence,
mc.Data,
mc.[XML],
CASE
WHEN mr.MovementIdentifier IS NULL
THEN 'true'
ELSE 'false'
END AS AccessDenied
FROM MovementRelationship mr
JOIN CardCollection cc
ON mr.RelationshipIdentifier = cc.CardIdentifier
JOIN EntityRelationship er
ON er.RelationshipIdentifier = cc.CardIdentifier
AND er.Relationship = 'Card'
JOIN EntityRelationship er2
ON er2.EntityIdentifier = er.EntityIdentifier
AND er2.Relationship = 'Affiliate'
AND er2.RelationshipIdentifier = @ReferrerIdentifier
RIGHT JOIN MovementCollection mc
ON mc.MovementIdentifier = mr.MovementIdentifier
May 6, 2009 at 5:18 am
firstly, thanks for all the replies...
ive tried various options, but so far the use of a CTE gives me the best result
though i am still busy testing
Are there any disadvantages to using a CTE in my stored proc??
WITH AccessDenied( CardIdentifier ) AS
(
SELECT DISTINCT
CardIdentifier
FROM
CardCollection AS cc
INNER JOIN EntityRelationship AS er ON cc.CardIdentifier = er.RelationshipIdentifier
INNER JOIN EntityRelationship AS er2 ON er2.Relationship = 'Affiliate'
AND
er2.RelationshipIdentifier = @ReferrerIdentifier
AND
er2.EntityIdentifier = er.EntityIdentifier
WHERE
er.Relationship = 'Card'
)
SELECT
mc.MovementIdentifierContext,
mc.MovementIdentifier,
mc.MovementIdentifierSequence,
mc.Data,
mc.[XML],
CASE WHEN ad.CardIdentifier IS NULL THEN 'true' ELSE 'false' END
FROM
MovementCollection mc
INNER JOIN MovementRelationship mr ON mc.MovementIdentifier = mr.MovementIdentifier
LEFT OUTER JOIN AccessDenied AS ad ON ad.CardIdentifier = RelationshipIdentifier
May 6, 2009 at 5:48 am
I dont't know the datamodel, but perhaps you can remove the DISTINCT in the CTE for further optimization?
May 6, 2009 at 6:18 am
anyone?
I was waiting for you to post up the samples I requested, partner. 😉
By failing to do that, you have people guessing at solutions... which may be wasting both their time and yours. Please take time to read the article here[/url] before submitting your next question. If you follow that format, you will get much quicker replys, the solutions are more likely to be right the first time, and you will make friends among the volunteers who are helping you out. Thanks. 🙂
__________________________________________________
Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills
May 6, 2009 at 6:51 am
sorry bout that, will follow posting hints better next time
May 6, 2009 at 6:53 am
No problem. Did any of the answers posted work for you?
__________________________________________________
Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills
May 6, 2009 at 7:05 am
all of it worked with some minor tweaking but the CTE worked the best, its weird though because i was testing the use of a table variable but wasnt seeing that much of a difference compared to a CTE.
Got the proc down from 41 sec (yes i know its ridiculous) down to 31ms....
:w00t:
May 6, 2009 at 7:14 am
What's ridiculous about cutting 25% of the work out? If you can do that with everything that runs on your SQL server, you are doing well.
__________________________________________________
Against stupidity the gods themselves contend in vain. -- Friedrich Schiller
Stop, children, what's that sound? Everybody look what's going down. -- Stephen Stills
May 6, 2009 at 7:54 am
The way I read it: Execution time is 31ms instead of 41000ms. That's a big difference! 😀
Viewing 15 posts - 1 through 15 (of 18 total)
You must be logged in to reply to this topic. Login to reply