My first query from table takes about 40 seconds and creates over 80,000 rows. I want to get the counts of Windows 7 applications by Site, Sequence, Total and any OS version.
These sub-queries work, but of course they slow the process down considerably. It took 3.5 hours to run.
Is there a more efficient way to do this?
Output:
SoftwareName Sequence Site Win7/site Win7Installs/seq TotWin7apps TotalInstalls
Adobe Acrobat 1 BKN 1 5 626 7854
AutoCAD LT 1 BKN 1 1 3 15
Adobe Acrobat 1 CTW 4 5 626 7854
Adobe Captivate 1 CTW 1 1 8 60
Query:
WITH PCapps AS (
SELECT DISTINCT
Computer,
Sequence,
Site,
SoftwareName,
OS
FROM table
)
SELECT DISTINCT
SoftwareName,
Sequence,
Site,
(SELECT COUNT(p1.SoftwareName) FROM PCapps p1 WHERE p1.SoftwareName = pc.Softwarename AND OS = 'Windows 7 Enterprise' AND p1.Site = pc.Site) as 'Win7/site',
(SELECT COUNT(p1.SoftwareName) FROM PCapps p1 WHERE p1.SoftwareName = pc.Softwarename AND OS = 'Windows 7 Enterprise' AND p1.Sequence = pc.Sequence) as 'Win7Installs/seq',
(SELECT COUNT(p2.SoftwareName) FROM PCapps p2 WHERE p2.SoftwareName = pc.Softwarename AND OS = 'Windows 7 Enterprise') as TotWin7apps,
(SELECT COUNT(p3.SoftwareName) FROM PCapps p3 WHERE p3.SoftwareName = pc.SoftwareName) as TotalInstalls
FROM PCapps pc
** UPDATE:
Using the tips from @Jason Carter, I created a few #temp tables and join them. The result runs very fast in less than a minute (not much longer than the initial query). This method is slightly different than @JasonCarter's solution as I was following his initial tip to create #temp tables. I created several #temp tables, each including the COUNT()s.
SELECT DISTINCT
Computer,
Sequence,
Site,
SoftwareName,
OS
INTO #PCapps
FROM TABLE
SELECT
SoftwareName,
Site,
COUNT(SoftwareName) AS [SiteInstalls]
INTO #SiteInstalls
FROM #PCapps
WHERE OS = 'Windows 7 Enterprise'
GROUP BY Site, SoftwareName
SELECT
SoftwareName,
Sequence,
COUNT(SoftwareName) AS [SeqInstalls]
INTO #SeqInstalls
FROM #PCapps
WHERE OS = 'Windows 7 Enterprise'
GROUP BY Sequence, SoftwareName
SELECT
SoftwareName,
COUNT(SoftwareName) AS [Win7Installs]
INTO #Win7Installs
FROM #PCapps
WHERE OS = 'Windows 7 Enterprise'
GROUP BY SoftwareName
SELECT
SoftwareName,
COUNT(SoftwareName) AS [AppInstalls]
INTO #AppInstalls
FROM #PCapps
GROUP BY SoftwareName
SELECT
pc.SoftwareName,
pc.Sequence,
pc.Site,
sit7.SiteInstalls,
seq7.SeqInstalls,
w7.Win7Installs,
ai.AppInstalls
FROM #PCapps pc
LEFT OUTER JOIN #SiteInstalls sit7 ON sit7.SoftwareName = pc.SoftwareName AND sit7.Site = pc.Site
LEFT OUTER JOIN #SeqInstalls seq7 ON seq7.SoftwareName = pc.SoftwareName AND seq7.Sequence = pc.Sequence
LEFT OUTER JOIN #Win7Installs w7 ON w7.SoftwareName = pc.SoftwareName
LEFT OUTER JOIN #AppInstalls ai ON ai.Softwarename = pc.SoftwareName
DROP TABLE #PCapps
DROP TABLE #SiteInstalls
DROP TABLE #SeqInstalls
DROP TABLE #Win7Installs
DROP TABLE #AppInstalls
Really surprising to me... The optimizer takes advantage of parallelism to make the subqueries very efficient. I populated a dummy table with 120K records and tried the below. The third query is only slightly more efficient than the first (yours), but at the cost of more complexity. I would leave yours as-is. There probably is a better solution, but yours looks good enough to me. How long does yours take to process the 80K rows?
First query: Table 'pcapps'. Scan count 15, logical reads 6630, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Second query: Table 'pcapps'. Scan count 3, logical reads 1326, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table 'Worktable'. Scan count 18, logical reads 1983591, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Third query: Table 'pcapps'. Scan count 12, logical reads 5304, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
I would try running the subqueries first into a temp table to gather your counts, then pull your total counts. With the way you have the query setup its going to run each of those subqueries once for every line of PCapps, which is why it is taking so long.
Try something like this: