图片 4

CPU开销分析,语句查询常用的

**1、对查询进行优化,应尽量避免全表扫描,首先应考虑在
where 及 order by 涉及的列上建立索引。 

一. 概述

  上次在介绍性能调优中讲到了I/O的开销查看及维护,这次介绍CPU的开销及维护,
在调优方面是可以从多个维度去发现问题如I/O,CPU, 
内存,锁等,不管从哪个维度去解决,都能达到调优的效果,因为sql
server系统作为一个整体性,它都是紧密相连的,例如:解决了sql语句中I/O开销较多的问题,那对应的CPU开销也会减少,反之解决了CPU开销最多的,那对应I/O开销也会减少。解决I/O开销后CPU耗时也减少,是因为CPU下的Worker线程需要扫描I/O页数就少了,出现的资源锁的阻塞也减少了,具体可参考cpu的原理。

  下面sql语句的dmv:sys.dm_exec_query_stats和sys.dm_exec_sql_text
已经在上篇”sql server 性能调优 I/O开销分析“中有讲到。

--查询编译以来 cpu耗时总量最多的前50条(Total_woker_time)
SELECT TOP 50
    total_worker_time/1000 AS [总消耗CPU 时间(ms)],
    execution_count [运行次数],
    qs.total_worker_time/qs.execution_count/1000 AS [平均消耗CPU 时间(ms)],
    last_execution_time AS [最后一次执行时间],
    max_worker_time /1000 AS [最大执行时间(ms)],
    SUBSTRING(qt.text,qs.statement_start_offset/2+1, 
        (CASE WHEN qs.statement_end_offset = -1 
        THEN DATALENGTH(qt.text) 
        ELSE qs.statement_end_offset END -qs.statement_start_offset)/2 + 1) 
    AS [使用CPU的语法], qt.text [完整语法],
    qt.dbid, dbname=db_name(qt.dbid),
    qt.objectid,object_name(qt.objectid,qt.dbid) ObjectName
FROM sys.dm_exec_query_stats qs WITH(nolock)
CROSS apply sys.dm_exec_sql_text(qs.sql_handle) AS qt
WHERE execution_count>1
ORDER BY  total_worker_time DESC

查询如下图所示,显示CPU耗时总量最多的前50条

图片 1

在排名第38条,拿出耗时的sql脚本来分析,发现未走索引。如下图

图片 2

SELECT [PO_NO],[Qty] FROM [ORD_PurchaseLine] WITH(NOLOCK) WHERE ([PO_NO] IN (' ')) 

图片 3

阅读目录

2、应尽量避免在 where
子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。 

二. 维护注意点

  1. 
在生产数据库下,CPU耗时查询,并不限定只排查总耗时前50条,可以是前100~200条。具体看sql脚本没有没优化的需要,并不是每个表的查询都必须走索引。如:有的表不走索引时并不会感觉很耗时平均I/0次数少,表中已建的索引已有多个,增删改也频繁,还有索引占用空间,这时需要权衡。 

-- 快速查看索引数量
sp_help [RFQ_PurDemandDetail]

  图片 4

 2. 不要在工作时间维护大表索引

   
当我们排查到有的大表缺失索引,数据在100w以上,如果在工作时间来维护索引,不管是创建索引还是重建索引都会造成表的阻塞,
这里表的响应会变慢或者直接卡死,前端应用程序直接请求超时。这里需要注意的。来看下新建一个索引的脚本会发现
开启了行锁与页锁(ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON)。

CREATE NONCLUSTERED INDEX [ix_createtime] ON [dbo].[PUB_Search_Log] 
(
    [CreateTime] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF,
 IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO
  • 一、SQL分类
  • 二、基础语句
  • 三、sql技巧
  • 四、(MS SQL
    Server)SQL语句导入导出大全

3、应尽量避免在 where 子句中对字段进行 null
值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: 
select id from t where num is null 
可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: 
select id from t where num=0 

回到目录

4、应尽量避免在 where 子句中使用 or
来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如: 
select id from t where num=10 or num=20 
可以这样查询: 
select id from t where num=10 
union all 
select id from t where num=20 

一、SQL分类

DDL—数据定义语言(CREATE,ALTER,DROP,DECLARE)

DML—数据操纵语言(SELECT,DELETE,UPDATE,INSERT)

DCL—数据控制语言(GRANT,REVOKE,COMMIT,ROLLBACK)

 

回到目录

5、下面的查询也将导致全表扫描: 
select id from t where name like ‘%abc%’ 
若要提高效率,可以考虑全文检索。 

二、基础语句

6、in 和 not in 也要慎用,否则会导致全表扫描,如: 
select id from t where num in(1,2,3) 
对于连续的数值,能用 between 就不要用 in 了: 
select id from t where num between 1 and 3 

2.1、说明:创建数据库

create database db-name

7、如果在 where
子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描: 
select id from t where num=@num 
可以改为强制查询使用索引: 
select id from t with(index(索引名)) where num=@num 

2.2、说明:删除数据库

drop database db-name 

8、应尽量避免在 where
子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如: 
select id from t where num/2=100 
应改为: 
select id from t where num=100*2 

2.3、说明:备份sql server

--- 创建 备份
USE master
EXEC sp_addumpdevice 'disk', 'testBack', 'c:mssql7backupMyNwind_1.dat'
--- 开始 备份
BACKUP DATABASE pubs TO testBack

9、应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如: 
select id from t where substring(name,1,3)=’abc’–name以abc开头的id 
select id from t where
datediff(day,createdate,’2005-11-30′)=0–‘2005-11-30’生成的id 
应改为: 
select id from t where name like ‘abc%’ 
select id from t where createdate>=’2005-11-30′ and
createdate<‘2005-12-1’ 

2.4、说明:创建新表

create table tabname(col1 type1 [not null] [primary key],col2 type2 [not null],..)根据已有的表创建新表:
A:create table tab_new like tab_old (使用旧表创建新表)
B:create table tab_new as select col1,col2… from tab_old definition only

10、不要在 where
子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。 

2.5、说明:删除新表

drop table tabname

11、在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。 

2.6、说明:增加一个列

Alter table tabname add column col type

注:列增加后将不能删除。DB2中列加上后数据类型也不能改变,唯一能改变的是增加varchar类型的长度。

2.7、说明:添加/删除主键

Alter table tabname add primary key(col)
Alter table tabname drop primary key(col)

2.8、说明:创建/删除索引

create [unique] index idxname on tabname(col….)
drop index idxname

注:索引是不可更改的,想更改必须删除重新建。

2.9、说明:创建/删除视图

create view viewname as select statement
drop view viewname

12、不要写一些没有意义的查询,如需要生成一个空表结构: 
select col1,col2 into #t from t where 1=0 
这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样: 
create table #t(…) 

2.10、说明:基本sql语句选择

图片 5

查询:select * from table1 where 范围
插入:insert into table1(field1,field2) s(1,2)
删除:delete from table1 where 范围
更新:update table1 set field1=1 where 范围
查找:select * from table1 where field1 like ’%1%’ ---like的语法
排序:select * from table1 order by field1,field2 [desc]
总数:select count * as totalcount from table1
求和:select sum(field1) as sum from table1
平均:select avg(field1) as avg from table1
最大:select max(field1) as max from table1
最小:select min(field1) as min from table1

图片 6

13、很多时候用 exists 代替 in 是一个好的选择: 
select num from a where num in(select num from b) 
用下面的语句替换: 
select num from a where exists(select 1 from b where num=a.num) 

2.11、说明:高级查询运算

A: UNION
运算符

UNION
运算符通过组合其他两个结果表(例如 TABLE1 和
TABLE2)并消去表中任何重复行而派生出一个结果表。

当 ALL 随
UNION 一起使用时(即 UNION ALL),不消除重复行。

两种情况下,派生表的每一行不是来自
TABLE1 就是来自 TABLE2。

B: EXCEPT
运算符

EXCEPT
运算符通过包括所有在 TABLE1 中但不在 TABLE2
中的行并消除所有重复行而派生出一个结果表。

当 ALL 随
EXCEPT 一起使用时 (EXCEPT ALL),不消除重复行。

C:
INTERSECT 运算符

INTERSECT
运算符通过只包括 TABLE1 和 TABLE2
中都有的行并消除所有重复行而派生出一个结果表。

当 ALL 随
INTERSECT 一起使用时 (INTERSECT ALL),不消除重复行。

注:使用运算词的几个查询结果行必须是一致的。

14、并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。 

2.12、说明:使用外连接

A、left
outer join:
左外连接(左连接):结果集几包括连接表的匹配行,也包括左连接表的所有行。

SQL: select
a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c

B:right
outer join:
右外连接(右连接):结果集既包括连接表的匹配连接行,也包括右连接表的所有行。

C:full
outer join:
全外连接:不仅包括符号连接表的匹配行,还包括两个连接表中的所有记录。

 

15、索引并不是越多越好,索引固然可以提高相应的 select
的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update
时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。 

补充:

1)、说明:复制表(只复制结构,源表名:a
新表名:b) (Access可用)

法一:select * into b from a where 1<>1

法二:select top 0 * into b from a

2)、说明:拷贝表(拷贝数据,源表名:a
目标表名:b) (Access可用)

insert into b(a, b, c) select d,e,f from b; 

3)、说明:跨数据库之间表的拷贝(具体数据使用绝对路径)
(Access可用)

insert into b(a, b, c) select d,e,f from b in ‘具体数据库’ where 条件

例子:..from b in '"&Server.MapPath(".")&"data.mdb" &"' where..

4)、说明:子查询(表名1:a
表名2:b)

select a,b,c from a where a IN (select d from b ) 或者: select a,b,c from a where a IN (1,2,3) 

5)、说明:显示文章、提交人和最后回复时间

select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b

6)、说明:外连接查询(表名1:a
表名2:b)

select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c 

7)、说明:在线视图查询(表名1:a
)

select * from (SELECT a,b,c FROM a) T where t.a > 1; 

8)、说明:between的用法,between限制查询数据范围时包括了边界值,not
between不包括

select * from table1 where time between time1 and time2
select a,b,c, from table1 where a not between 数值1 and 数值2

9)、说明:in
的使用方法

select * from table1 where a [not] in (‘值1’,’值2’,’值4’,’值6’) 

10)、说明:两张关联表,删除主表中已经在副表中没有的信息

delete from table1 where not exists ( select * from table2 where table1.field1=table2.field1 )

11)、说明:四表联查问题

select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where ..... 

12)、说明:日程安排提前五分钟提醒

SQL: select * from 日程安排 where datediff('minute',f开始时间,getdate())>5 

13)、说明:一条sql
语句搞定数据库分页

select top 10 b.* from (select top 20 主键字段,排序字段 from 表名 order by 排序字段 desc) a,表名 b where b.主键字段 = a.主键字段 order by a.排序字段

14)、说明:前10条记录

select top 10 * form table1 where 范围 

15)、说明:选择在每一组b值相同的数据中对应的a最大的记录的所有信息(类似这样的用法可以用于论坛每月排行榜,每月热销产品分析,按科目成绩排名,等等.)

select a,b,c from tablename ta where a=(select max(a) from tablename tb where tb.b=ta.b) 

16)、说明:包括所有在
TableA 中但不在 TableB和TableC
中的行并消除所有重复行而派生出一个结果表

(select a from tableA ) except (select a from tableB) except (select a from tableC) 

17)、说明:随机取出10条数据

select top 10 * from tablename order by newid() 

18)、说明:随机选择记录

select newid()

19)、说明:删除重复记录

Delete from tablename where id not in (select max(id) from tablename group by col1,col2,...) 

20)、说明:列出数据库里所有的表名

select name from sysobjects where type='U'

21)、说明:列出表里的所有的

select name from syscolumns where id=object_id('TableName') 

22)、说明:列示type、vender、pcs字段,以type字段排列,case可以方便地实现多重选择,类似select
中的case。

select type,
sum(case vender when 'A' then pcs else 0 end),
sum(case vender when 'C' then pcs else 0 end),
sum(case vender when 'B' then pcs else 0 end)
FROM tablename group by type

显示结果:

图片 7

type vender pcs
电脑 A 1
电脑 A 1
光盘 B 2
光盘 A 2
手机 B 3
手机 C 3

图片 8

23)、说明:初始化表table1

TRUNCATE TABLE table1 

24)、说明:选择从10到15的记录

select top 5 * from (select top 15 * from table order by id asc) table_别名 order by id desc

 

回到目录

16、应尽可能的避免更新 clustered 索引数据列,因为 clustered
索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新
clustered 索引数据列,那么需要考虑是否应将该索引建为 clustered 索引。 

三、sql技巧

发表评论

电子邮件地址不会被公开。 必填项已用*标注

标签:
网站地图xml地图