2011-05-04 39 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