2011-05-04 33 views
3

我很難解決我在下面發佈的問題。基數估計問題?日期時間參數vs cast?

這裏是我的問題:

如果我在SQL Server同治工作室運行下面的確切查詢或利用.NET SQLCLIENT的查詢需要14秒的平均運行。

然而,如果在.NET我取出查詢的該部分:

DECLARE @time_diff INT 
DECLARE @start_date DATETIME 
DECLARE @end_date DATETIME 

SET @time_diff = 2 
SET @start_date = '05/04/11 00:00:00 AM' 
SET @end_date = '5/4/2011 11:59:59 PM' 

和使用參數在這樣的代碼:

sqlParameter = sqlCmd.Parameters.Add(New SqlParameter("@start_date", System.Data.SqlDbType.DateTime)) 
sqlParameter.Value = parameters.StartDate 
sqlParameter = sqlCmd.Parameters.Add(New SqlParameter("@end_date", System.Data.SqlDbType.DateTime)) 
sqlParameter.Value = parameters.EndDate 

那麼查詢大約需要2 - 3分鐘跑步。


另外,我注意到,大約需要2 - 3分鐘跑,如果我用繩子日期常量替換參數值,並在.NET或SSMS運行

--AND v.call_start_time BETWEEN @start_date AND @end_date 
AND v.call_start_time BETWEEN '05/04/11' AND '5/4/2011 11:59:59 PM' 

我發現這有關基數和查詢優化器的文章http://msdn.microsoft.com/en-us/library/ms175933%28SQL.90%29.aspx,我認爲它與我的問題有關,但對我而言似乎沒有意義。 根據文章,在決定基數時應該執行演員。在我的情況下,這似乎並沒有發生。這篇文章還說使用參數來代替局部變量 - 這對於.NET參數來說也不是很好。

使用存儲過程,而不是關於: 我有一個可變數量的參數,我不知道它會如何工作的。即使這是唯一的選擇,那麼我仍然想知道問題到底是什麼。

查詢:

DBCC DROPCLEANBUFFERS 
DBCC FREEPROCCACHE 

SET STATISTICS IO ON 

DECLARE @time_diff INT 
DECLARE @start_date DATETIME 
DECLARE @end_date DATETIME 

SET @time_diff = 2 
SET @start_date = '05/04/11 00:00:00 AM' 
SET @end_date = '5/4/2011 11:59:59 PM' 

--INSERT QUERY 
SELECT * INTO ##tmp_15 FROM (-- PRI CALL RECORDINGS SEARCH QUERY: 
    SELECT DISTINCT 
    v.call_recording_id, 
    v.call_start_time, 
    v.call_source, 
    v.call_type, 
    IsNull(v.phone, '') AS phone, 
    d.call_duration_seconds AS pri_call_duration_seconds, 
    IsNull(cdr.extension, 'N/A') AS pri_extension, 
    IsNull(users.last_name, 'N/A') AS pri_last_name, 
    IsNull(users.first_name, 'N/A') AS pri_first_name, 
    NULL AS debtor_no, 
    NULL AS d_extension, 
    NULL AS d_last_name, 
    NULL AS d_first_name 
    FROM tbl_call_recordings AS v 
    JOIN tbl_pri_call_details AS d ON v.call_recording_id = d.call_recording_id 
    LEFT JOIN (
     SELECT extension, phone, call_start_time 
     FROM tbl_pri_cdr_records 
     WHERE is_discard = 0 
    ) AS cdr ON v.phone = cdr.phone AND 
     ABS(DATEDIFF(mi, v.call_start_time, cdr.call_start_time)) <= @time_diff 

    -- MATCH RECORDS TO USER INFO VIA EXTENSION 
    LEFT JOIN (
     SELECT extension, 
       start_date, 
       IsNull(end_date, GETDATE()) AS end_date, 
       usr.user_id, 
       last_name, 
       first_name, 
       cr_user_id 
     FROM tbl_extensions AS ext 
     JOIN tbl_extension_users AS ext_usr ON ext.id = ext_usr.extension_id 
     JOIN tbl_users AS usr ON ext_usr.user_id = usr.user_id 
    ) AS users ON cdr.extension = users.extension 
    AND v.call_start_time BETWEEN users.start_date AND users.end_date 
    WHERE 1 = 1 

    -- INSERT PRI SEARCH CONSTRAINTS HERE: 
    AND v.call_start_time BETWEEN @start_date AND @end_date 
    --AND v.call_start_time BETWEEN '05/04/11' AND '5/4/2011 11:59:59 PM' 

UNION 

-- DIALER RECORDINGS SEARCH QUERY: 
     SELECT 
     v.call_recording_id, 
     v.call_start_time, 
     v.call_source, 
     v.call_type, 
     IsNull(v.phone, '') AS phone, 
     NULL AS pri_call_duration_seconds, 
     NULL AS pri_extension, 
     NULL AS pri_last_name, 
     NULL AS pri_first_name, 
     d.debtor_no, 
     IsNull(users.extension, 'N/A') AS extension, 
     IsNull(users.last_name, 'N/A') AS last_name, 
     IsNull(users.first_name, 'N/A') AS first_name 
     FROM tbl_call_recordings AS v 
     JOIN tbl_dialer_call_details AS d ON v.call_recording_id = d.call_recording_id 

     -- MATCH RECORDS TO USER INFO VIA EXTENSION 
     LEFT JOIN (
       SELECT extension, 
         start_date, 
         IsNull(end_date, GETDATE()) AS end_date, 
         last_name, 
         first_name, 
         cr_user_id 
       FROM tbl_extensions AS ext 
       JOIN tbl_extension_users AS ext_usr ON ext.id = ext_usr.extension_id 
       JOIN tbl_users AS usr ON ext_usr.user_id = usr.user_id 

    ) as users ON d.agent = users.cr_user_id 
     AND v.call_start_time BETWEEN users.start_date AND users.end_date 
     WHERE 1 = 1 
     -- INSERT DIALER SEARCH CONSTRAINTS HERE: 
    AND v.call_start_time BETWEEN @start_date AND @end_date 
    --AND v.call_start_time BETWEEN '05/04/11' AND '5/5/2011' 
)t 
+2

所以你得到更好的** **比當有機會看看實際值的變量的表現?也許你需要更新該表的統計數據。 – 2011-05-05 00:08:04

+0

是的,我使用變量獲得了更好的性能 - 但只有在sql中聲明並設置時。在.NET中使用參數時,性能是2-3分鐘而不是15秒。如果.NET參數沒有執行,更新統計信息是否仍然有意義? – 2011-05-05 00:27:25

+0

是的,我認爲是。我認爲這些參數值仍然被嗅探。 – 2011-05-05 01:22:04

回答

1

看來,更改數據,因爲統計信息的最後更新都可能有根據目前的考慮在範圍內的不成比例的影響這意味着統計此刻降權誤導並需要手動更新。

A good article discussing this issue is here.

+0

條適合我的情況完美。日期時間聚集索引,每天2500萬條記錄+ 60K。我正在運行的查詢也正在尋找最後的記錄。看起來我必須設置一個時間表來更新統計信息。 – 2011-05-05 16:24:11