当前位置: 代码迷 >> Sql Server >> 视图查询时快时慢的有关问题
  详细解决方案

视图查询时快时慢的有关问题

热度:95   发布时间:2016-04-24 08:46:50.0
视图查询时快时慢的问题!
一个复杂的 SQL2012商用数据库,对某一个视图(包含3个表)的查询时快时慢,比如:
8am - 11am 平均时间不到1秒; 
11am-13pm 平均时间有8秒;
13pm-17pm 平均时间不到2秒。

而且每天的规律都不一样,有可能是一大早很慢;下午就快。
唯一的规律是:都是呈“时间段”出现的,并且只是影响这个视图的查询,不影响其他的性能。

这样的情况回事很么原因呢?考虑可能是索引的问题,但是索引的问题不应该是呈“时间段”出现的。
需要一个办法来查明原因。 但是这个数据库是在被使用中,所以不能做任何有损性能的调试。
------解决思路----------------------

我觉得可能有2个原因:

1.在特定时间段,数据库比较繁忙,导致原来较快的sql,在这个是时间段慢了。

2.全天的这3个时间段,负载差不多,那么可能是 这3个时间段内 执行视图时,产生的执行计划是不同的,建议分别抓取这3个时间段内的 sql的执行计划来分析。

还有一个问题就是,你这视图,在这3个时间段内执行,每次的查询条件都一样吗,还是会变化?
------解决思路----------------------
这种情况,感觉机器负载的影响可能性会大一点

可以先检查你在执行速度快和慢的时候,分别观察下机器本身内存和CPU的使用情况。
------解决思路----------------------
引用:
感谢大家的回复。

观察了2周,还是有同样的问题。
请问版主,如果抓取这三个时间段的执行计划,是不是抓取期间会对当时系统的性能造成影响??





Quote: 引用:


我觉得可能有2个原因:

1.在特定时间段,数据库比较繁忙,导致原来较快的sql,在这个是时间段慢了。

2.全天的这3个时间段,负载差不多,那么可能是 这3个时间段内 执行视图时,产生的执行计划是不同的,建议分别抓取这3个时间段内的 sql的执行计划来分析。

还有一个问题就是,你这视图,在这3个时间段内执行,每次的查询条件都一样吗,还是会变化?


应该还不至于会对性能有大的影响。
------解决思路----------------------
IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].Proc_DBA_GetSlowSQL') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].Proc_DBA_GetSlowSQL
GO
-- =============================================
-- Author: yng
-- Create date: 2014-12-17
-- Description: 取得最近执行缓慢的SQL语句
-- =============================================
CREATE PROCEDURE dbo.Proc_DBA_GetSlowSQL
@topNum INT = 50 --取前多少条记录
,@lastExecutionTime DATETIME = NULL --最后执行时间, 默认为NULL. 为 NULL 则忽略此条件; 不为NULL 则取大于此参数之后执行的
,@excludeNight BIT=1 --是否 排除晚上的信息? 默认=1 排除。选择是=1,后面两参数才有意义
,@nightBegin CHAR(5)='22:00' --"晚上"开始时间点, 默认 22:00
,@nightEnd CHAR(5)='06:00' --"晚上"结束时间点, 默认 06:30
,@containSQL NVARCHAR(300)=NULL --语句中包含的SQL. 默认为NULL. 为NULL则忽略此条件; 不为NULL则取包含此参数的记录
AS
BEGIN
SET NOCOUNT ON
DECLARE @nightBegin_num INT
DECLARE @nightEnd_num INT
SET @nightBegin_num=CAST( replace(@nightBegin,':','') AS INT)
SET @nightEnd_num=CAST( replace(@nightEnd,':','') AS INT)

SET ROWCOUNT @topNum
SELECT 
st.text AS SQL_Full --父级完整语句
,SUBSTRING(st.text, (qs.statement_start_offset/2) + 1,
((CASE statement_end_offset 
WHEN -1 THEN DATALENGTH(st.text)
ELSE qs.statement_end_offset END 
- qs.statement_start_offset)/2) + 1) as SQL_Part --统计对应的部分语句
, CAST( ((qs.total_elapsed_time / 1000000.0)/qs.execution_count) AS DECIMAL(28,2) ) AS [平均消耗秒数]
, CAST(qs.last_elapsed_time / 1000000.0 AS DECIMAL(28, 2)) AS [最后完成消耗秒数]
, qs.last_execution_time AS [最后执行时间]
, CAST(qs.min_elapsed_time / 1000000.0 AS DECIMAL(28, 2)) AS [最小消耗秒数]
, CAST(qs.max_elapsed_time / 1000000.0 AS DECIMAL(28, 2)) AS [最大消耗秒数]
, CAST(qs.total_elapsed_time / 1000000.0 AS DECIMAL(28, 2)) AS [总消耗秒数]
, (qs.execution_count) AS [总执行次数]
, creation_time AS [编译计划的时间]
, CAST(qs.last_worker_time / 1000000.0 AS DECIMAL(28, 2)) AS [最后完成占用CPU秒数]
, sql_handle,statement_start_offset,statement_end_offset
,plan_generation_num,plan_handle,creation_time
,last_execution_time,execution_count
,total_worker_time,last_worker_time,min_worker_time,max_worker_time
,total_physical_reads,last_physical_reads,min_physical_reads,max_physical_reads,total_logical_writes,last_logical_writes,min_logical_writes,max_logical_writes,total_logical_reads,last_logical_reads,min_logical_reads,max_logical_reads
,total_clr_time,last_clr_time,min_clr_time,max_clr_time
    from sys.dm_exec_query_stats qs
        CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
WHERE
--1. 最后执行时间 
(@lastExecutionTime IS NULL OR qs.last_execution_time>=@lastExecutionTime)
--2. 包含 SQL 条件 
AND
(@containSQL IS NULL OR st.[text] LIKE '%'+@containSQL+'%')
AND
--3. 是否排除晚上
(
@excludeNight=0 
OR
(
--2.1 开始大于结束 22:00->6:30 [ x >=6:30(end) and x<22:00(begin) ]
@nightBegin_num>@nightEnd_num AND
(
CAST( replace(CONVERT(varchar(5),last_execution_time,108),':','') AS INT)>=@nightEnd_num
AND
CAST( replace(CONVERT(varchar(5),last_execution_time,108),':','') AS INT)<@nightBegin_num
)
)
OR
(
--2.2 开始小于结束 1:00->6:30 [ x>=0:00 and x<1:00 or x>=6:30 and x<24:00 ]
@nightBegin_num<@nightEnd_num AND
(
(
CAST( replace(CONVERT(varchar(5),last_execution_time,108),':','') AS INT)>=0
AND
CAST( replace(CONVERT(varchar(5),last_execution_time,108),':','') AS INT)<@nightBegin_num
)
OR
(
CAST( replace(CONVERT(varchar(5),last_execution_time,108),':','') AS INT)>=@nightEnd_num
AND
CAST( replace(CONVERT(varchar(5),last_execution_time,108),':','') AS INT)<2400
)
)
)
)
ORDER BY qs.last_elapsed_time DESC

SET NOCOUNT OFF
SET ROWCOUNT 0
END
GO

--示例:在今天的 11:00 查今天 08:00 到现在最慢的SQL
EXEC dbo.Proc_DBA_GetSlowSQL
@topNum = 50 --取前多少条记录
,@lastExecutionTime = '2015-10-07 08:00' --最后执行时间, 默认为NULL. 为 NULL 则忽略此条件; 不为NULL 则取大于此参数之后执行的
,@excludeNight =1 --是否 排除晚上的信息? 默认=1 排除。选择是=1,后面两参数才有意义
,@nightBegin ='22:00' --"晚上"开始时间点, 默认 22:00
,@nightEnd ='06:00' --"晚上"结束时间点, 默认 06:30
,@containSQL =NULL


------解决思路----------------------
引用:
多谢yenange,根据上面的语句的确列出了一些执行慢的语句,然后根据 [最后完成消耗秒数] 倒叙排列。
但是怎样根据这些返回语句来分析问题所在呢?


--1. 你应该点右下角的“引用我, 这样我看到的更快。
--2. 找到一些慢的sql 之后, 可以分析到底是哪些查询是比较慢的, 综合分析。
--3. 视图中建议表名后带 with(nolock) , 这样查询时不必带 sx 锁;
--4. 一般下午是用户访问高峰期, 如果你这个视图相关联的表相当大(上千万), 而且并发访问多, 下午慢是正常的;
--5. 让运维监控这台DB服务器的 cpu 和 磁盘IO 情况,特别是IO,要测试一下最高能到多少, 如果服务器IO不行(低于100MB/S), 对数据查询确实有很大影响。
--6. 你最好是把视图的创建语句、相关的查询语句及对应的执行计划列出来, 这样众高手才方便帮你看有没有改进余地。