- This topic has 16 replies, 10 voices, and was last updated 11 years ago by technicallyinept.
-
tsql help
-
mrmoFree Member
after some advice about how to do this quicker. currently 15mins
i am doing a sum of sales orders where a specific product has been bought then dividing by a sum of all salesorders,
can anyone offer a way of speeding this up?
code attached in case anyone can think of some ideas. (the no locks are only to stop me crucifing the database whilst getting this to work. )
select ccx_sopsystemaccountid, horsepercent,name,address1_postalcode,owneridname, horse, allsales, ccx_coresegmentname, ccx_industryname
from
(select a.ccx_sopsystemaccountid, horse/allsales horsepercent ,name,address1_postalcode,owneridname, horse, allsales, ccx_coresegmentname, ccx_industryname
from
(select ccx_sopsystemaccountid,horse ,name,address1_postalcode,owneridname, ccx_coresegmentname, ccx_industryname
from
(SELECT FilteredAccount.ccx_sopsystemaccountid, filteredaccount.name,FilteredAccount.owneridname, filteredaccount.address1_postalcode,sum(FilteredSalesOrderDetail.baseamount)horse, ccx_coresegmentname, ccx_industryname
FROM FilteredAccount WITH (nolock) INNER JOIN
FilteredSalesOrder WITH (nolock) ON FilteredAccount.accountid = FilteredSalesOrder.accountid INNER JOIN
FilteredSalesOrderDetail WITH (nolock) ON FilteredSalesOrder.salesorderid = FilteredSalesOrderDetail.salesorderid INNER JOIN
FilteredProduct WITH (nolock) ON FilteredProduct.productid = FilteredSalesOrderDetail.productid
WHERE (FilteredAccount.statecodename = ‘active’) and submitstatusdescription=’invoiced’
AND (FilteredProduct.ccx_productcategoryidname in (‘PRI-Equest Feed & Bed’,’PRI-Equest Accessories’) or FilteredProduct.ccx_productgroupidname = ‘BMS-Horse’)
AND (FilteredSalesOrder.ccx_cog_invoicedate BETWEEN CONVERT(DATETIME, ‘2012-01-01 00:00:00’, 102) AND CONVERT(DATETIME, ‘2012-12-31 00:00:00’, 102))
group by FilteredAccount.ccx_sopsystemaccountid, filteredaccount.name, filteredaccount.address1_postalcode,filteredaccount.owneridname, ccx_coresegmentname, ccx_industryname
)aa
where horse>500
)a
inner join
(SELECT FilteredAccount.ccx_sopsystemaccountid, sum(FilteredSalesOrderDetail.baseamount)allsales
FROM FilteredAccount WITH (nolock) INNER JOIN
FilteredSalesOrder WITH (nolock) ON FilteredAccount.accountid = FilteredSalesOrder.accountid INNER JOIN
FilteredSalesOrderDetail WITH (nolock) ON FilteredSalesOrder.salesorderid = FilteredSalesOrderDetail.salesorderid INNER JOIN
FilteredProduct WITH (nolock) ON FilteredProduct.productid = FilteredSalesOrderDetail.productid
WHERE (FilteredAccount.statecodename = ‘active’) and submitstatusdescription=’invoiced’
AND (FilteredSalesOrder.ccx_cog_invoicedate BETWEEN CONVERT(DATETIME, ‘2012-01-01 00:00:00’, 102) AND CONVERT(DATETIME, ‘2012-12-31 00:00:00’, 102))
group by FilteredAccount.ccx_sopsystemaccountid)b
on a.ccx_sopsystemaccountid=b.ccx_sopsystemaccountid
where horse/allsales>0.25)aaafrogstompFull MemberMight be better to summarise your table structures/relationships and what you want to achieve so people can suggest a solution from scratch rather than trying to decypher a mass of spaghetti SQL code..?
mrmoFree Membercould do,
briefly account table links inner join to order table, to salesorderdetail to product. where product is specific
divide by above but no filter on product.
BigEaredBikerFree MemberWhat version of SQL Server are you using?
I’d suggest you post so DDL so we can use http://sqlfiddle.com/ to create a mock up and play with your T-SQL in there.
P.S. I am not a SQL Developer so the chances that I can help you are very slim…
leffeboyFull MemberStupid question but is FilteredSalesOrder.ccx_cog_invoicedate indexed?
leffeboyFull MemberThe real question is whether or not that particular field is indexed as it is unlikely that every field in every table it indexed. At the moment that is where I would start looking
The other place is the function ‘horse/allsales>0.25’ that you have. That has to be calculated for each record. You might find that 4 * horse>allsales runs faster or if it can be removed that might be even better.
duckersFree MemberAs per leffeboy’s comments, also get rid of any multiple function calls doing the same thing and replace with constants or variables i.e:
CONVERT(DATETIME, ‘2012-01-01 00:00:00’, 102) AND CONVERT(DATETIME, ‘2012-12-31 00:00:00’, 102))
to
DECLARE @Start DATETIME = CONVERT(DATETIME, ‘2012-01-01 00:00:00’, 102)
DECLARE @End DATETIME = CONVERT(DATETIME, ‘2012-12-31 00:00:00’, 102)
….. cog_invoicedate BETWEEN @Start and @EndYou could break the query into smaller chunks and insert into table variables or CTE’s, also analyse the query execution plan for poor performing steps (doing it against your large query wold be a pita) and this will give you some hints on missing indexes.
Importantly, (again stealing leffeboys thunder a little) run the SQL profiler and/or index tuning wizard to identify columns should be indexed (you should probably do at least those you join on and in a WHERE clause); this will give you the biggest benefit as it will do the work for you and in 99% of cases will give you a marked improvement.
Last but not least you could hire someone to re-write it for you and improve performance (email in profile, payment in cash, bike bits, or biscuits)!
leffeboyFull Memberagain stealing leffeboys thunder a little
you can have it, my wife doesn’t appreciate it 🙂
allthepiesFree Memberhorse ? 🙄
Lovely for when someone else has to maintain the code.
retro83Free MemberChange your unique identifiers for statuses, categories and so on to be numeric rather than varchars. Depending on how you’ve got it indexed, it can be 50% slower.
chvckFree MemberTo be fair I don’t think that is ever going to be lovely to maintain!
toby1Full MemberDoes tsql implement the with clause? that might at least make it easier to read and remove the subqueries.
technicallyineptFree MemberCan you clarify what you’re after?
Is it (for a given date period), for each accountid, the sum of horse sales, the sum of all sales and the percentage of horse sales, where the percentage is > 0.25?
technicallyineptFree MemberI’m sure you have solved this by this now but, if not, give this a whirl (obviously untested)
/* Basic data */
;WITH cte as(
(SELECT fa.ccx_sopsystemaccountid AS AccountID, fsod.baseamount, fp.ccx_productgroupidname as GroupName, fp.ccx_productcategoryidname as CatName
FROM FilteredAccount AS fa WITH (nolock)
INNER JOIN FilteredSalesOrder AS fso WITH (nolock) ON fso.accountid = fa.accountid
INNER JOIN FilteredSalesOrderDetail AS fsod WITH (nolock) ON fsod.salesorderid = fso.salesorderid
INNER JOIN FilteredProduct AS fp WITH (nolock) ON fp.productid = fsod.productid
WHERE (ac.statecodename = ‘active’)
AND submitstatusdescription=’invoiced’
AND (fso.ccx_cog_invoicedate BETWEEN CONVERT(DATETIME, ‘2012-01-01 00:00:00’, 102) AND CONVERT(DATETIME, ‘2012-12-31 00:00:00’, 102))
)
/* Sales value */
,TotalsByAccount AS
(
SELECT g1.AccountID, g1.TotalSales, g2.TotalHorse FROM
(SELECT AccountID, SUM(baseamount) AS TotalSales
FROM cte
GROUP BY AccountID) AS g1
INNER JOIN
(SELECT AccountID, SUM(baseamount) as TotalHorse
FROM cte
WHERE GroupName = ‘BMS-Horse’ OR CatName = ‘PRI-Equest Feed & Bed’ OR CatName = ‘PRI-Equest Accessories’
GROUP BY AccountID
HAVING Horse > 500) AS g2 ON g2.AccountId = g1.AccountID
)
/* Final output */
SELECT AccountID, TotalSales, TotalHorse, (TotalHorse/TotalSales * 100) AS PercentageHorse
, name, address1_postalcode, owneridname, ccx_coresegmentname, ccx_industryname
FROM TotalsByAccount AS t
INNER JOIN FilteredAccount AS fa
ON fa.ccx_sopsystemaccountid = t.AccountID
WHERE (TotalHorse/TotalSales > 0.25);
The topic ‘tsql help’ is closed to new replies.