Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2008 Forums
 Transact-SQL (2008)
 Query performance issue

Author  Topic 

keyursoni85
Posting Yak Master

233 Posts

Posted - 2012-02-02 : 02:37:40
Hi, I wrote below query in procedure with multiple filters in it but it is taking too much time when i filter with all criteria specified.

My table structure:
Partmaster
>> Part part reference table holds part id and part referenceid for single part
>> Units (which will include part reference id for parts)
>> Part reference table will store part reference information.

Requirements:
>> I want part's unit count by its number of part reference specified in part part reference table.
>> I also want last sold price from unit table and also min and max price for that part from unit table.


-------------------
ALTER PROCEDURE [dbo].[usp_getUnitSalesSummary]
@PartCategoryID INT = 0,
@Manufacturers VARCHAR(1000) = '',
@PartReferences VARCHAR(1000) = '',
@PartID INT = 0,
@PartReferenceID INT = 0,
@PropertyCodeValuesFilters VARCHAR(1000) = '',
@Grades VARCHAR(100) = '',
@CustomerID INT = 0
AS
BEGIN
-- List of manufacturer passed in string with comma seperated manufactuerer names
DECLARE @TblManufacturers AS TABLE(ManufacturerID INT)
IF (@Manufacturers <> '')
BEGIN
INSERT INTO @TblManufacturers (ManufacturerID)
SELECT M.ID
FROM dbo.fnSplitString(@Manufacturers, ',') tmpM
INNER JOIN tbl_Manufacturer M ON LTRIM(RTRIM(M.manufacturer)) = LTRIM(RTRIM(tmpM.Data))
END

DECLARE @ObjectTypeID AS INT;

SELECT @ObjectTypeID = ObjectTypeID
FROM tbl_ObjectTypes
WHERE archived = 0
AND ObjectTypeCode = 'Part';

-- List part ids for filter.
DECLARE @TblPart AS TABLE(PartId INT)
INSERT INTO @TblPart (PartId)
SELECT ObjectID
FROM dbo.fn_getPropertyValueObjects (@PropertyCodeValuesFilters, @ObjectTypeID)

SELECT
top 10
pm.ID AS 'PartID',
PartNumber,
PartDescription,
isnull(pm.CreatedUserID , 0) AS 'CreatedUserID',
ISNULL(pm.AuthorisedUserID, 0) AS 'AuthorisedUserID',
ISNULL(pm.AuthorisedDate, '') AS 'AuthorisedDate',
ISNULL(pm.Authorised, 0) AS 'Authorised',
m.ID AS 'ManufacturerID',
m.man AS 'ManufacturerCode',
m.manufacturer AS 'ManufacturerName',
pc.PartCategoryID AS 'PartCategoryID',
pc.PartCategoryCode AS 'PartCategoryCode',
pc.PartCategoryName AS 'PartCategoryName',
pc.CertifyDataSafe AS 'CertifyDataSafe',
pc.InterfaceID AS 'InterfaceID',
'-' AS 'InterfaceCode',
'-' AS 'InterfaceName',
'-' AS 'interfacedesc',
'' OEM1,
'' OEM2,
'' OEM3,
'' OEM4,
TotalUnitCount
FROM
-- get a distinct list of Part IDs that meet our filter criteria
(
select
pm.ID,
COUNT(1) OVER (PARTITION BY pm.id) TotalUnitCount
from
tbl_PartsMaster AS pm
INNER JOIN @TblPart tblPartIds ON tblPartIds.PartId = pm.ID
INNER JOIN tbl_PartCategories AS pc ON pc.PartCategoryID = pm.PartCategoryID
INNER JOIN tbl_PartPartReferences AS ppr ON pm.ID = ppr.PartID
INNER JOIN tbl_PartReferences AS pr ON ppr.PartReferenceID = pr.PartReferenceID
INNER JOIN tbl_Manufacturer AS m ON pr.ManufacturerID = m.ID

INNER JOIN dbo.fnSplitString(@PartReferences, ',') PRIDs ON (LTRIM(RTRIM(PRIDs.Data)) = pr.Reference OR @PartReferences = '')

LEFT JOIN tbl_Units AS u ON u.PartReferenceID = ppr.PartReferenceID
LEFT JOIN tbl_ActivityRequest AR ON AR.ActID = u.ACTID
--LEFT JOIN @TblManufacturers tblManu ON (tblManu.ManufacturerID = pm.[OEM] OR @Manufacturers = '')

INNER JOIN dbo.fnSplitString(@Grades, ',') tbGrades ON (LTRIM(RTRIM(tbGrades.Data)) = u.Grade OR @Grades = '')
-- u.Grade IN (SELECT LTRIM(RTRIM(Data)) FROM dbo.fnSplitString(@Grades, ','))
-- pr.Reference IN (SELECT LTRIM(RTRIM(Data)) FROM dbo.fnSplitString(@PartReferences, ','))
where
pm.archived = 0
AND
pr.archived = 0
AND
ppr.archived = 0
AND
pc.archived = 0
AND
(
pm.ID = @PartID
OR
@PartID = 0
)
AND
(
pm.PartCategoryID = @PartCategoryID
OR
@PartCategoryID = 0
)
AND
(
pr.PartReferenceID = @PartReferenceID
OR
@PartReferenceID = 0
)
AND
(
AR.OID = @CustomerID
OR
@CustomerID = 0
)
) AS p
INNER JOIN tbl_PartsMaster AS pm ON p.ID = pm.ID
INNER JOIN tbl_Manufacturer AS m ON pm.OEM = m.ID
INNER JOIN tbl_PartCategories AS pc ON pm.PartCategoryID = pc.PartCategoryID
WHERE
ISNULL(pm.archived, 0) = 0
group by
pm.ID,
PartNumber,
PartDescription,
isnull(pm.CreatedUserID , 0),
ISNULL(pm.AuthorisedUserID, 0),
ISNULL(pm.AuthorisedDate, ''),
ISNULL(pm.Authorised, 0),
m.ID,
m.man,
m.manufacturer,
pc.PartCategoryID,
pc.PartCategoryCode,
pc.PartCategoryName,
pc.CertifydataSafe,
pc.InterfaceID, TotalUnitCount
ORDER BY
PartNumber;

END
/*
-- testing
-- usp_getUnitSalesSummary @CustomerID = 308, @manufacturers = 'dell', @grades = 'D'
-- usp_getUnitSalesSummary @partid = 138013
*/
GO


Please help.

GilaMonster
Master Smack Fu Yak Hacker

4507 Posts

Posted - 2012-02-02 : 04:32:52
http://sqlinthewild.co.za/index.php/2009/03/19/catch-all-queries/

--
Gail Shaw
SQL Server MVP
Go to Top of Page

keyursoni85
Posting Yak Master

233 Posts

Posted - 2012-02-02 : 04:49:31
Hi,
Thanks but I also tried with dynamic query..

And found cause that unit table join takes too much time
Is it due to reason that.. part master .. to part part references and part references to unit table's part reference id join??

That join only takes time in query upto 20+ seconds.. If I remove that condition and then it retuns upto 500 rows in 1 second.

Can I do anything with that unit table join and its unit count for any part differently?
Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2012-02-02 : 05:12:32
[code]
LEFT JOIN tbl_Units AS u ON u.PartReferenceID = ppr.PartReferenceID
[/code]
That one? Have you got an index on tbl_Units.PartReferenceID ? what about tbl_PartPartReferences.PartReferenceID ?

Does SSMS recommend any additional indexes?
[code]
INNER JOIN dbo.fnSplitString(@PartReferences, ',') PRIDs ON (LTRIM(RTRIM(PRIDs.Data)) = pr.Reference OR @PartReferences = '')
[/code]
Personally I would put the TRIM functions inside the fnSplitString function, and possibly use an OUTER JOIN??
[code]
LEFT OUTER JOIN dbo.fnSplitString(@PartReferences, ',') PRIDs ON PRIDs.Data
...
WHERE
...
AND (PRIDs.Data IS NOT NULL OR @PartReferences = '')
[/code]
dunno if that will make any difference though.

You're doing the same TRIMming with fnSplitString on tbl_Manufacturer :
[code]
INNER JOIN tbl_Manufacturer M ON LTRIM(RTRIM(M.manufacturer)) = LTRIM(RTRIM(tmpM.Data))
[/code]
only that one is even worse because you are also doing "LTRIM(RTRIM((M.manufacturer))" - you need to get all those superfluous spaces out of your stored data so you can just JOIN the columns without functions. SQL won't use an index if you wrap a column with a function.
[code]
WHERE
ISNULL(pm.archived, 0) = 0
[/code]
changing that to
[code]
(pm.archived = 0 OR pm.archived IS NULL)
[/code]
might give you better index selection (but that's not going to be highly relevant to the issue at hand). SQL may "unwind" that function anyway.

What's the point of your OVER ... PARTITION BY? You aren't checking the ROWNO (it doesn't even have an alias name ...), you could just as easily use DISTINCT or GROUP BY there, or move all the columns required for the SELECT into the OVER ... PARTITION BY section.
[code]
DECLARE @TblManufacturers AS TABLE(ManufacturerID INT)
[/code]
Probably worth putting a Primary key on @TblManufacturers
[code]
GROUP BY isnull(pm.CreatedUserID , 0),
ISNULL(pm.AuthorisedUserID, 0),
ISNULL(pm.AuthorisedDate, ''),
ISNULL(pm.Authorised, 0),
[/code]
Can any of these columns, such as [CreatedUserID], actually have a ZERO value? If not then skip the ISNULL and the GROUP BY will group them on NULL or their value. If you DO need GROUP BY to treat CreatedUserID =NULL and CreatedUserID = 0 as one-and-the-same then I think you should look at your data and NOT store BOTH Null and Zero in that column - one-or-the-other.

If those columns can be a ZERO value what about these?
[code]

pm.ID = @PartID
OR
@PartID = 0
[/code]
if pm.ID can ALSO be a Zero Value then you have no means of just selecting pm.ID = 0 (because it is your wildcard value ...). For this reason we always use NULL as our wildcard @parameter value
[code]
ISNULL(pm.AuthorisedDate, '')
[/code]
Is [AuthorisedDate] column NOT a DateTime (or DATE) datatype? If so surely it should be? If not then you can't use a blank-string as the second parameter, its not a valid date "value".
Go to Top of Page

keyursoni85
Posting Yak Master

233 Posts

Posted - 2012-02-02 : 05:30:44
Thank you,

I applied some changes in my sp suggested above and also applied outer apply for unit table due to performance issue and query now takes appx 3-4 seconds but ..
when I include filter for manufacturers (with join) or with part references (with join) it takes so much time..

I also gathered IDs for those comma seperated values seperately at start of sp and then applied join..

Because I want to use join in that way if manufacturers not passed then it simple returns results therefor I wrote or condition.

Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2012-02-02 : 09:27:21
So: Answers to these earlier questions pls:

"Have you got an index on tbl_Units.PartReferenceID ? what about tbl_PartPartReferences.PartReferenceID ?

Does SSMS recommend any additional indexes?
"
Go to Top of Page

keyursoni85
Posting Yak Master

233 Posts

Posted - 2012-02-02 : 10:20:07
yes, i created non clustered index on that column unit table. and it is working fine now with small amount of time.
But still I think query can be optimized more.
Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2012-02-02 : 11:54:55
I look to see what the logical I/O and Scans are, and try to reduce those (well ... I look at the ones with highest numbers first!)

I also look at query plan to see where PKey is being used where I would expect an index to be used, and then try to work out why the index is not being used, or if a better index could be created.

Then I look at whether the indexes that ARE being used could (sensibly) be changed to COVER more of the query.
Go to Top of Page
   

- Advertisement -