2012-05-12 52 views
0

我需要幫助優化或重寫此複雜查詢。查詢對於有50行的測試數據非常有效,但真正的數據現在有超過700,000行,查詢需要5分鐘才能運行。我在這兩個表的主鍵上有索引。我相信年齡功能的成本很高,就好像我拿出來一樣,大約節省了2分半鐘。任何建議表示讚賞。提前致謝。優化或重寫使用多個公用表表達式的透視查詢

WITH T AS (
     SELECT TOP 2000 
      A.Residence_City, 
      CASE 
      WHEN A.Gender = 'M' then 'Male' 
      WHEN A.Gender = 'F' then 'Female' 
      WHEN A.Gender = 'U' then 'Unknown' 
     END AS Gender, 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 18 and 24 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 0 then 1 else null end) as [0_3_18], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 18 and 24 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 1 then 1 else null end) as [1_3_18], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 18 and 24 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 2 then 1 else null end) as [2_3_18], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 18 and 24 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 3 then 1 else null end) as [3_3_18], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 18 and 24 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 0 then 1 else null end) as [Unknown_18], 

count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 25 and 34 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 0 then 1 else null end) as [0_3_25], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 25 and 34 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 1 then 1 else null end) as [1_3_25], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 25 and 34 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 2 then 1 else null end) as [2_3_25], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 25 and 34 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 3 then 1 else null end) as [3_3_25], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 25 and 34 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 0 then 1 else null end) as [Unknown_25], 

count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 35 and 49 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 0 then 1 else null end) as [0_3_35], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 35 and 49 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 1 then 1 else null end) as [1_3_35], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 35 and 49 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 2 then 1 else null end) as [2_3_35], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 35 and 49 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 3 then 1 else null end) as [3_3_35], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 35 and 49 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 0 then 1 else null end) as [Unknown_35], 

count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 50 and 64 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 0 then 1 else null end) as [0_3_50], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 50 and 64 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 1 then 1 else null end) as [1_3_50], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 50 and 64 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 2 then 1 else null end) as [2_3_50], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 50 and 64 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 3 then 1 else null end) as [3_3_50], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 50 and 64 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 0 then 1 else null end) as [Unknown_50], 

count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 65 and 120 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 0 then 1 else null end) as [0_3_65], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 65 and 120 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 1 then 1 else null end) as [1_3_65], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 65 and 120 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 2 then 1 else null end) as [2_3_65], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 65 and 120 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 3 then 1 else null end) as [3_3_65], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) between 65 and 120 and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 0 then 1 else null end) as [Unknown_65], 

count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) = '' or voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE())is null and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 0 then 1 else null end) as [0_3_], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) = '' or voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE())is null and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 1 then 1 else null end) as [1_3_], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) = '' or voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE())is null and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 2 then 1 else null end) as [2_3_], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) = '' or voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE())is null and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 3 then 1 else null end) as [3_3_], 
count(case when voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE()) = '' or voterData.dbo.ufn_GetAge (convert(datetime,[Date_of_Birth]), GETDATE())is null and voterData.dbo.GeneralVoting (V.[G10EC], V.[G08EC],V.[G06EC]) = 0 then 1 else null end) as [Unknown_] 

from Personal as A INNER JOIN Voting_History V 
on A.Vuid = V.Vuid 
group by Residence_City, Gender with rollup 
Order by Residence_City, Gender 
) 
, temp1 as (
    SELECT *,([3_3_18] + [3_3_25] + [3_3_35] + [3_3_50] + [3_3_65] + [3_3_] 
       +[2_3_18] + [2_3_25] + [2_3_35] + [2_3_50] + [2_3_65] + [2_3_] 
       +[1_3_18] + [1_3_25] + [1_3_35] + [1_3_50] + [1_3_65] + [1_3_] 
       +[0_3_18] + [0_3_25] + [0_3_35] + [0_3_50] + [0_3_65] + [0_3_] 
      +[Unknown_18]+ [Unknown_25]+ [Unknown_35] + [Unknown_50]+ [Unknown_65] + [Unknown_]) Total 
FROM T 
where NULLIF(Residence_City,'') IS NOT NULL 
), temp2 as (
    SELECT * FROM temp1 
UNION ALL 
select 
'grand Total', 
SUM([0_3_18])/2,SUM([1_3_18])/2,SUM([2_3_18])/2,SUM([3_3_18])/2,SUM([Unknown_18])/2, 
SUM([0_3_25])/2,SUM([1_3_25])/2,SUM([2_3_25])/2,SUM([3_3_25])/2,SUM([Unknown_25])/2, 
SUM([0_3_35])/2,SUM([1_3_35])/2,SUM([2_3_35])/2,SUM([3_3_35])/2,SUM([Unknown_35])/2, 
SUM([0_3_50])/2,SUM([1_3_50])/2,SUM([2_3_50])/2,SUM([3_3_50])/2,SUM([Unknown_50])/2, 
SUM([0_3_65])/2,SUM([1_3_65])/2,SUM([2_3_65])/2,SUM([3_3_65])/2,SUM([Unknown_65])/2, 
SUM([0_3_])/2,SUM([1_3_])/2,SUM([2_3_])/2,SUM([3_3_])/2,SUM([Unknown_])/2, 
sum(Total)/2 

FROM temp1 
) 

SELECT Residence_City, Gender, 
    [0_3_18]  as [0_3], 
    [1_3_18]  as [1_3], 
    [2_3_18]  as [2_3], 
    [3_3_18]  as [3_3], 
    [Unknown_18] as [Unknown], 

    [0_3_25]  as [0_3], 
    [1_3_25]  as [1_3], 
    [2_3_25]  as [2_3], 
    [3_3_25]  as [3_3], 
    [Unknown_25] as [Unknown], 

    [0_3_35]  as [0_3], 
    [1_3_35]  as [1_3], 
    [2_3_35]  as [2_3], 
    [3_3_35]  as [3_3], 
    [Unknown_35] as [Unknown], 

    [0_3_35]  as [0_3], 
    [1_3_35]  as [1_3], 
    [2_3_35]  as [2_3], 
    [3_3_35]  as [3_3], 
    [Unknown_35] as [Unknown], 

    [0_3_35]  as [0_3], 
    [1_3_35]  as [1_3], 
    [2_3_35]  as [2_3], 
    [3_3_35]  as [3_3], 
    [Unknown_35] as [Unknown], 

    [0_3_35]  as [0_3], 
    [1_3_35]  as [1_3], 
    [2_3_35]  as [2_3], 
    [3_3_35]  as [3_3], 
    [Unknown_35] as [Unknown], 
    Total 
    FROM temp2 

這些功能

ALTER FUNCTION [dbo].[GeneralVoting] (@one varchar, @two varchar,@three varchar) 
    RETURNS INT 
    AS 
    BEGIN 

     DECLARE @vAge   INT 

     SET @vAge = (CASE WHEN @one IS NOT NULL THEN 1 ELSE 0 END) 
         +(CASE WHEN @two IS NOT NULL THEN 1 ELSE 0 END) 
         +(CASE WHEN @three IS NOT NULL THEN 1 ELSE 0 END) 
    RETURN @vAge 
    END 

而且

ALTER FUNCTION [dbo].[ufn_GetAge] (@pDateOfBirth DATETIME, @pAsOfDate DATETIME) 
    RETURNS INT 
    AS 
    BEGIN 
     DECLARE @vAge   INT 
     IF @pDateOfBirth >= @pAsOfDate 
      RETURN 0 

     SET @vAge = DATEDIFF(YY, @pDateOfBirth, @pAsOfDate) 

     IF MONTH(@pDateOfBirth) > MONTH(@pAsOfDate) OR 
      (MONTH(@pDateOfBirth) = MONTH(@pAsOfDate) AND 
      DAY(@pDateOfBirth) > DAY(@pAsOfDate)) 
      SET @vAge = @vAge - 1 
     RETURN @vAge 
    END 

回答

0

的加入似乎結構合理。我不確定是否需要彙總,但它可能不會影響性能。

我懷疑用戶定義的函數影響性能。 SQL Server沒有足夠的智能來優化對ufn_GetAge()的多次調用,所以函數被反覆調用。相反,把年齡在子查詢:

(select *, voterData.dbo.ufn_GetAge(convert(datetime,[Date_of_Birth]), GETDATE()) as age 
from VoterData 
) age 

功能是相當簡單的,所以你也可以取代它在網上,以消除這一個電話。

您也可以對其他功能採用相同的方法。

此外,投票和個人歷史表有多大?特別是,城市和性別有多少種組合?您可以通過預選最高2000年,然後對不同的組進行計算,使查詢更有效。儘管不知道尺寸,但很難說這是否有效。另外,你真的打算由Residence_City訂購性別嗎? 。 。或者你想要通過其他領域之一訂購?現在,查詢只是按字母順序選擇第一個。

+0

這兩張表格各有45列,共有31個城市和3個性別組合。實際上排名前2000的應該是前100萬,因爲查詢應該記錄所有記錄。對於排序,它並不重要。我正在嘗試子查詢建議,謝謝你的幫助。 – user973671

+0

您的建議將查詢時間降低到22秒。巨大的改進,謝謝你的時間。 – user973671