SQL比较重要的知识点

1.聚集索引和非聚集索引的区别

  Page是数据库存储的最小单位,聚集索引的叶节点存储的是真正的数据页;非聚集索引的叶节点存储的是指向数据页的索引键值和指针。

  索引键值存储的就是建立索引的列的值(字段值)
  SQLServer获取数据,总是以页为单位,就算是只读取一行也会获取整张页
  仅非聚集索引--最终页节点存储的是索引键值和RID,其实也是一个一个的页(Page)
  仅聚集索引--叶节点就是真正的数据页(Page),页中数据排序规则是按照索引键值进行排序
  索引中间页--存储的是索引的每一行,每一行存储的是索引键值和指针(指针可能指向数据页或者继续指向中间页)
  在既有聚集索引又有非聚集索引的情况下,每
个叶级节点所指向的是该聚集索引的索引键值,即数据记录本身。

 

2.主键就是聚集索引吗?

  开始设置的ID为自动增长列,但是并未设置主键,在索引信息里面没看到有索引,接着设置了ID为主键后,系统自动建立了索引。

有些文章说的是信息表并不适合建立主键,也就是不适合在ID列上建立索引,而是应该在经常要查询的条件上建立聚集索引(某个字段)。

 

3.单一聚集索引和复合聚集索引的区别

   单一索引是指索引列为一列的情况,即新建索引的语句只实施在一列上。

   用户可以在多个列上建立索引,这种索引叫做复合索引(组合索引)。

   复合索引的创建方法与创建单一索引的方法完全一样。但复合索引在数据库操作期间所需的开销更小,可以代替多个单一索引。当表的行数远远大于索引键的数目时,使用这种方式可以明显加快表的查询速度。窄索引是指索引列为1-2列的索引,如果不特殊说明的话一般是指单一索引。宽索引也就是索引列超过2列的索引。设计索引的一个重要原则就是能用窄索引不用宽索引,因为窄索引往往比组合索引更有效。

   建立复合索引的例子:

         CREATE UNIQUE CLUSTERED INDEX CLIDX_OrderDetails  ON dbo.OrderDetails(SalesOrderID,SalesOrderDetailID)

   如果仅用聚集索引的起始列作为查询条件和同时用到复合聚集索引的全部列的查询速度是几乎一样的,甚至比用上全部的复合索引列还要略快(在查询结果集数目一样的情况下);而如果仅用复合聚集索引的非起始列作为查询条件的话,这个索引是不起任何作用的。无论您是否经常使用聚合索引的其他列,但其前导列一定要是使用最频繁的列。

   (1)对一张表来说,如果有一个复合索引 on   (col1,col2),就没有必要同时建立一个单索引 on col1。

  (2)如果查询条件需要,可以在已有单索引 on col1的情况下,添加复合索引on   (col1,col2),对于效率有一定的提高。
  (3)
同时建立多字段(包含5、6个字段)的复合索引没有特别多的好处,相对而言,建立多个窄字段(仅包含一个,或顶多2个字段)的索引可以达到更好的效率和灵活性。

 

4.不适合建立聚集索引的条件

   (1)频繁更改的列.这将导致整行移动(因为 SQL Server 必须按物理顺序保留行中的数据值)。这一点要特别注意,因为在大数据量事务处理系统中数据是易失的。

   (2)宽键.来自聚集索引的键值由所有非聚集索引作为查找键使用,因此存储在每个非聚集索引的叶条目内。

 

5.什么时候适用于非聚集索引?

   (1)包含大量非重复值的列,如姓氏和名字的组合(如果聚集索引用于其它列)。如果只有很少的非重复值,如只有 1 和 0,则大多数查询将不使用索引,因为此时表扫描通常更有效。

   (2)不返回大型结果集的查询。

   (3)返回精确匹配的查询的搜索条件(WHERE 子句)中经常使用的列。

   (4)经常需要联接和分组的决策支持系统应用程序。应在联接和分组操作中使用的列上创建多个非聚集索引,在任何外键列上创建一个聚集索引。

   (5)在特定的查询中覆盖一个表中的所有列。这将完全消除对表或聚集索引的访问。

   索引都是一种排序,只是聚集索引的排序和物理表中的数据排序相同,一致的;而非聚集索引的排序和物理表数据的排序不同。

 

    当我们在更新统计信息的时候,对于那些聚集索引列不但要更新索引页还要同时对数据物理表数据重新排序;而对非聚集索引列则只需要更新索引页。

 

 

6.索引碎片的整理

   索引碎片是这样一种情形:由于在表里大量的插入、修改、删除操作而使索引页分裂。如果索引有了高的碎片,有两种情况,一种情况是扫描索引需要花费很多的时间,另一种情况是在查询的时候索引根本不使用索引,都会导致性能降低。

 

  有2种类型的碎片:

  内部破碎:由于索引页里的数据插入或修改操作而发生,以数据作为稀疏矩阵的形式的分布而结束,这将导致数据页的增加,从而增加查询时间。

  外部破碎:由于索引/数据页的数据插入或修改而发生,以页码分离和在文件系统里不连贯的新的索引页的分配而结束,数据库服务器不能利用预读操作的优点,因为:下一个相关联的数据页不临近,而且这些相关连的下面的页码可能在数据文件的任何地方。

 

  检测是否有碎片的方法:

    (1)以你的目标数据库的名字取代AdventureWorks

  SELECT object_name(dt.object_id) Tablename,si.name, 

  IndexName,dt.avg_fragmentation_in_percent AS
  ExternalFragmentation,dt.avg_page_space_used_in_percent AS
  InternalFragmentation
  FROM
  (
  SELECT object_id,index_id,avg_fragmentation_in_percent,avg_page_space_used_in_percent
  FROMsys.dm_db_index_physical_stats(db_id('AdventureWorks'),null,null,null,'DETAILED'
  )
  WHERE index_id<>0)AS dt INNERJOIN sys.indexessiONsi.object_id=dt.object_id
  AND si.index_id=dt.index_id AND dt.avg_fragmentation_in_percent>10
  AND dt.avg_page_space_used_in_percent<75 ORDERBY avg_fragmentation_in_percentDESC

 

   ExternalFragmentation的值>10,预示对应的索引出现外部碎片。InternalFragmentation的值<75,预示对应的索引出现内部碎片

 

   (2)ShowPlan_All

        显示查询计划是SQL在执行查询的过程中查看哪些索引被采用,可以设置查询计划的开关On Off

        set showplan_all on
        go
        select * from admin_t

        go
        set showplan_all off

   (3)Statistics Io

         数据查询过程中出现的磁盘活动量,也是性能的表现之一,可以设置开关On Off

         set statistics io on
         go
         select * from admin_t
         go
         set statistics io off

         (1 行受影响)
         表 'admin_t'。扫描计数 1,逻辑读取 2 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次

 

  索引的维护

 在创建索引之后,随着时间的推移,由于用户对表的添加删除更新等,使得数据变得杂乱无序,影响索引的性能,所以需要经常对索引进行整理,更新。

(1)统计信息更新

我们在创建索引的时候,SQL会存储有关的统计信息。因为查询优化器会根据统计信息进行查询的成本进行计算,所以,如果统计信息过时了就会导致查询优化器的查询方法不是最优的。

我们一般对索引进行更新的方法语句是:update statistics admin_t PK_admin_t 中间是空格 不是点 .

(2)使用DBCC SHOWCONTIG语句扫描表

对表进行操作可能会产生碎片,而碎片可能会产生额外的页,从而降低数据查询性能。通过扫描表查询并通过返回值确定改索引的连续性达到多少,理想值是100%。

Dbcc Showcontig (admin_t,PK_admin_t) 是ShowContig 不是 ShowConfig,主要看他的扫描密度:

----------------------------------------------------------------

DBCC SHOWCONTIG 正在扫描 'admin_t' 表...
表: 'admin_t' (181575685);索引 ID: 1,数据库 ID: 5
已执行 TABLE 级别的扫描。
- 扫描页数................................: 1
- 扫描区数..............................: 1
- 区切换次数..............................: 0
- 每个区的平均页数........................: 1.0
- 扫描密度 [最佳计数:实际计数].......: 100.00% [1:1]
- 逻辑扫描碎片 ..................: 0.00%
- 区扫描碎片 ..................: 0.00%
- 每页的平均可用字节数........................: 8010.0
- 平均页密度(满).....................: 1.04%
DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。


(3)碎片整理DBCC INDEXDEFRAG

出现了严重的碎片,就要进行整理。dbcc indexdefrag(study,admin_t,PK_admin_t)

和扫描不同,他要加上数据库参数,是数据库--表--索引

在使用碎片进行整理的时候如果报这样的错误:无法重新组织表 "T_Info" 的索引 "T_S_Name_Index" (分区 1),因为已禁用页级锁定。只要在索引的属性中--选项--在访问索引时启用页锁 选中就可以了。

 

 

  接着重新整理索引碎片:

   (1)索引重组:执行 ALTER INDEX ALL ON TableName RECOGNIZE

   (2)索引重建:执行 ALTER INDEX ALL ON TableName REBUILD WITH(FILLFACTOR=90,=ON)

          通过使用具体索引的名字代替ALL,你能重组或重建单个的索引。你也可以使用数据库控制台来重建/重组索引

 

   什么时候建立索引重组还是重建索引

    当外部碎片的值在10-15,内部碎片的值在60-75,对于这样的索引,你应该重组索引。否则,你应该重建索引。

    关于索引重建的一个重要的事情是:一旦在一个特定的表上重建索引,表就会被锁定(重组的时候不会发生)。所以,对于一个产品数据库  的一个大的表,因为在一个大表上的索引重建往往需要花费数个小时,我们不希望这种锁定。幸运的是,在SQL2005有一个解决方法,你可  以在重建一个表的索引的时候,把ONLINE选项的值设为ON,这样会使重建索引和表上的数据事务同样进行。

    规则建议:
   如果你在从事一个事务性数据库,平均不要在一个表上创建超过5个索引,另外,如果你在从事数据仓库,平均最高可在一个表上创建10个   索引。

 

 7.数据分区

   表分区分为水平分区和垂直分区。水平分区将表分为多个表。每个表包含的列数相同,但是行更少。例如,可以将一个包含十亿行的表水平分区成 12 个表,每个小表表示特定年份内一个月的数据。任何需要特定月份数据的查询只需引用相应月份的表。而垂直分区则是将原始表分成多个只包含较少列的表。水平分区是最常用分区方式

 

    分区文件格式

       数据文件可以分为主数据文件和次数据文件:
主数据文件 扩展名为 .mdf 其包含数据库的启动信息和数据信息。
次数据文件 扩展名为 .ndf 其包含主数据文件没有包含的数据信息
使用次数据文件可以将数据分散在多个磁盘上以提高读取速度。如果数据库很大,大到单个数据文件大小超过单个WINDOWS文件的最大 大小时,就必须要使用次要数据文件,以便可以让数据库继续增长。
FAT16(Windows):支持最大分区2GB,最大文件2GB
FAT32(Windows):支持最大分区128GB,最大文件4GB
NTFS(Windows):支持最大分区2TB,最大文件2TB

 

    查看文件组信息:select * from sys.filegroups   其中is_read_only : 1 = 文件组为只读文件组 0=文件组为可读/写的文件组

 

    分区实例:

    大纲:

(1)创建逻辑文件组

(2)创建次要数据文件(ndf文件)并隶属文件组

(3)设置数据分区函数

(4)创建分区方案

(5)创建设置表

(6)查询数据在分区里面的详细统计信息

下面进行详细的设置:

1>创建文件组

alter database Study Add FileGroup [Study_1]

alter database Study Add FileGroup [Study_2]

alter database Study Add FileGroup [Study_3]

alter database Study Add FileGroup [Study_4]

2>设置文件到文件组

alter database Sudy Add File(Name=N'Stydu_1',FileName=N'd:/Study_1_F.ndf',Size=5M,FileGrowth=1M) TO FileGroup [Study_1]

alter database Sudy Add File(Name=N'Stydu_2',FileName=N'e:/Study_2_F.ndf',Size=5M,FileGrowth=1M) TO FileGroup [Study_2]

alter database Sudy Add File(Name=N'Stydu_3',FileName=N'f:/Study_3_F.ndf',Size=5M,FileGrowth=1M) TO FileGroup [Study_3]

alter database Sudy Add File(Name=N'Stydu_4',FileName=N'g:/Study_4_F.ndf',Size=5M,FileGrowth=1M) TO FileGroup [Study_4]

为了保持高效率的数据读写,尽量每个次要数据文件放在不同的磁盘阵列上。

3>创建分区函数

表进行分区的标准是通过分区函数来实现的。创建分区函数有Range Left 和Range Right两种情况,Range Left表示分区的上边界;Range Right表示分区的下边界。比如,你设置了四个分区,对于临界点,倘若你设置上边界可以这样设置:

create partition function [BookListF] (datetime) As Range Left For values ('20090131','20090228','20090331','20090430')

注意里面的时间段设置:

20090131--表示第一个分区的数据存放的是截止到2009-01-31的数据

20090228--表示第二个分区的数据存放的是截止到2009-02-28的数据

20090331--表示第三个分区的数据存放的是截止到2009-03-31的数据

20090430--表示第四个分区的数据存放的是截止到2009-04-30的数据

假如你设置下边界可以这样设置

create partition function [BookListF](datetime) As Range Right for values ('20090101','20090201','20090301')

注意里面的时间设置:

20090101--表示第一个分区的数据存放的是从2009-01-01开始截止到2009-02-01的数据

20090201--表示第一个分区的数据存放的是从2009-02-01开始截止到2009-03-01的数据

20090301--表示第一个分区的数据存放的是从2009-03-01开始的数据

从上面的分区设置我们就能看出不同的边界方式,设置的临界点数不同,还有需要注意的一点是:比如从2009-01-01开始表示的是从2009-01-01 00:00:00的数据,截止到2009-02-01的数据表示的是截止到2009-01-31 23:59:59

4>创建分区方案

create partition scheme [BookListS] As partition [BookListF] To([Study_1],[Study_2],[Study_3],[Study_4])

创建分区方案其实也就是定义存放数据的媒体和数据块之间的关系。多个数据表可以共同使用一个分区函数,但是不会共用相同的分区方案。

我们可以通过不同的分区方案使用相同的分区函数,使得不同的数据表有相同的分区条件,但是存放在不同的媒介上。

5>创建需要分区的数据表

create table TBook

(intID [int] IDENTITY[1,1] not null,

Description [varchar](100) null,

TDate [datetime] not null

)

on [BookListS](TDate)

注意最后一句:创建表绑定分区方案,并对应日期字段TDate

6>添加测试数据

insert into TBook values('11111','2009-01-02')

insert into TBook values('22222','2009-02-02')

insert into TBook values('33333','2009-03-02')

insert into TBook values('44444','2009-04-02')

insert into TBook values('55555','2009-01-02')


7>查询数据在分区的体现

SELECT $partition.BookListF(o.TDate)
AS [Partition Number]
, min(o.TDate) AS [Min Date]
, max(o.TDate) AS [Max Date]
, count(*) AS [Rows In Partition]
FROM dbo.TBook AS o
GROUP BY $partition.BookListF(o.TDate)
ORDER BY [Partition Number]

在出现的结果里在里面就能看到每个分区有多少记录(Rows In Patition对应的值),分区数(Partition Number)

 


8>撤销删除上面创建的信息

--删除表

drop table TBook

--删除分区方案

drop partition scheme [BookListS]

--删除分区函数

drop partition function [BookListF]

--删除文件和文件组

use master

alter database Study remove File [Study_1] --注意不是FileName的值,而是Name的值

alter database Study remove File [Study_2]

alter database Study remove File [Study_3]

alter database Study remove File [Study_4]

--删除文件组

alter database Study remove FileGroup [Study_1]

alter database Study remove FileGroup [Study_2]

alter database Study remove FileGroup [Study_3]

alter database Study remove FileGroup [Study_4]

有人可能会说,我现在的数据库中已经存在表了,要是还想分区怎么实现呢?这个其实更简单,你设置文件和文件组、创建分区函数、创建分区方案,就可以了,此时数据库中的数据就会按照你创建的文件保存进去了。你可以创建好分区方案之后,添加一部分数据,然后查询就能看到数据已经在不同的分区中了。

举例:未创建分区之前T-info中有5条记录

现在插入数据:insert into T_Info(CreateTime) values('2009-07-02')

由于临界点是20090701,并且采用的是Range Right方式,所以正常情况下,数据会保存在第二分区

SELECT $partition.[StudyFun](o.CreateTime)
AS [Partition Number]
, min(o.CreateTime) AS [Min SendDate]
, max(o.CreateTime) AS [Max SendDate]
, count(*) AS [Rows In Partition]
FROM dbo.T_Info AS o
GROUP BY $partition.[StudyFun](o.CreateTime)
ORDER BY [Partition Number]

查询结果如下图:显示在第二分区1条记录 

        只是不能针对某个表进行限制,也就是说数据库内的所有表都进行了分区,怎么对单个表进行分区呢?

 

 8.Sql模糊查询Like的新方式

    比如查找用户名包含有"c"的所有用户, 可以用
use mydatabase
select * from table1 where username like'%c%"


下面是完成上面功能的另一种写法:
use mydatabase
select * from table1 where charindex('c',username)>0

这种方法理论上比上一种方法多了一个判断语句,即>0, 但这个判断过程是最快的, 我想信80%以上的运算都是花在查找字符串及其它的运算上, 所以运用charindex函数也没什么大不了. 用这种方法也有好处, 那就是对%,|等在不能直接用like查找到的字符中可以直接在这charindex中运用, 如下:

use mydatabase
select * from table1 where charindex('%',username)>0

也可以写成:

use mydatabase
select * from table1 where charindex(char(37),username)>0

char(37) 的ASCII的字符即为:%

 

9.从外到内提高SQL Server数据库性能

 

      第一层:网络环境。

  到企业碰到数据库反映速度比较慢时,首先想到的是是否是网络环境所造成的。而不是一开始就想着如何去提高数据库的性能。这是很多数据库管理员的一个误区。因为当网络环境比较恶劣时,你就算再怎么去改善数据库性能,也是枉然。

  如以前有个客户,向笔者反映数据库响应时间比较长,让笔者给他们一个提高数据库性能的解决方案。那时,笔者感到很奇怪。因为据笔者所知,这家客户数据库的记录量并不是很大。而且,他们配置的数据库服务器硬件很不错。笔者为此还特意跑到他们企业去查看问题的原因。一看原来是网络环境所造成的。这家企业的客户机有200多台,而且都是利用集线器进行连接。这就导致企业内部网络广播泛滥,网络拥塞。而且由于没有部署企业级的杀毒软件,网络内部客户机存在病毒,掠夺了一定的带宽。不仅数据库系统响应速度比较慢,而且其他应用软件,如邮箱系统,速度也不理想。

  在这种情况下,即使再花十倍、百倍力气去提升SQL Server数据库的性能,也是竹篮子打水一场空。因为现在数据库服务器的性能瓶颈根本不在于数据库本身,而在于企业的网络环境。若网络环境没有得到有效改善,则SQL Server数据库性能是提高不上去的。

  为此,笔者建议这家企业,想跟他们的网络管理员谈谈,看看如何改善企业的网络环境,减少广播包和网络冲突;并且有效清除局域网内的病毒、木马等等。三个月后,我再去回访这家客户的时候,他们反映数据库性能有了很大的提高。而且其他应用软件,性能也有所改善。

  所以,当企业遇到数据库性能突然降低的时候,第一个反应就是查看网络环境,看看其实否有恶化。只有如此,才可以少走冤枉路。

  第二层:服务器配置。

  这里指的服务器配置,主要是讲数据库服务器的硬件配置以及周边配套。虽然说,提高数据库的硬件配置,需要企业付出一定的代价。但是,这往往是一个比较简便的方法。比起优化SQL语句来说,其要简单的多。

  如企业可以通过增加硬盘的数量来改善数据库的性能。在实际工作中,硬盘输入输出瓶颈经常被数据库管理员所忽视。其实,到并发访问比较多的时候,硬盘输入输出往往是数据库性能的一个主要瓶颈之一。此时,若数据库管理员可以增加几个硬盘,通过磁盘阵列来分散磁盘的压力,无疑是提高数据库性能的一个捷径。

  如增加服务器的内存或者CPU。当数据库管理员发现数据库性能的不理想是由内存或者CPU所造成的,此时,任何的改善数据库服务器本身的措施都将一物用处。所以,有些数据库管理专家,把改善服务器配置当作数据库性能调整的一个先决条件。

  如解决部署在同一个数据库服务器上的资源争用问题。虽然我们多次强调,要为数据库专门部署一个服务器。但是,不少企业为了降低信息化的成本,往往把数据库服务器跟应用服务器放在同一个服务器中。这就会导致不同服务器之间的资源争用问题。如把文件服务器跟数据服务器部署在同一个服务器中,当对文件服务器进行备份时,数据库性能就会有明显的下降。所以,在数据库性能发现周期性的变化时,就要考虑是否因为服务器上不同应用对资源的争夺所造成的。

  故,笔者建议,改善数据库性能时第二个需要考虑的层面,就是要看看能否通过改善服务器的配置来实现。


第三层:数据库服务器。

  当通过改善网络环境或者提高服务器配置,都无法达到改善数据库性能的目的时,接下去就需要考察数据库服务器本身了。首先,就需要考虑数据库服务器的配置。

  一方面,要考虑数据库服务器的连接模式。SQL Server数据库提供了很多的数据库模式,不同的数据库连接模式对应不同的应用。若数据库管理员能够熟悉企业自身的应用,并且选择合适的连接模式,这往往能够达到改善数据库性能的目的。

  其次,合理配置数据库服务器的相关作业。如出于安全的需要,数据库管理员往往需要对数据库进行备份。那么,备份的作业放在什么时候合适呢?当然,放在夜晚,夜深人静的时候,对数据库进行备份最好。另外,对于大型数据库,每天都进行完全备份将会是一件相当累人的事情。虽然累得不是我们,可是数据库服务器也会吃不消。差异备份跟完全备份结合将是改善数据库性能的一个不错的策略。

  第四层:数据库对象。

  若以上三个层面后,数据库性能还不能够得到大幅度改善的话,则就需要考虑是否能够调整数据库对象来完成我们的目的。虽然调整数据库对象往往可以提到不错的效果,但是,往往会对数据库产生比较大的影响。所以,笔者一般不建议用户一开始就通过调整数据库对象来达到改善数据库性能的目的。

  数据库对象有表、视图、索引、关键字等等。我们也可以通过对这些对象进行调整以实现改善数据库性能的目标。

  如在视图设计时,尽量把其显示的内容缩小,宁可多增加视图。如出货明细表,销售人员可能希望看到产品编号、产品中英文描述、产品名字、出货日期、客户编号、客户名字等等。但是,对于财务来说,可能就不需要这么全的信息。他们只需要产品编号、客户编号、出货日期等等少量的信息即可。所以,能可浪费一点代码的空间,设计两张视图,对应不同部门的需求。如此,财务部门在查询数据时,不会为不必要的数据浪费宝贵的资源。

  如可以通过合理设置索引来提高数据库的性能。索引对于提高数据的查询效率,有着非常好的效果。对一些需要重复查询的数据、或者数据修改不怎么多的表设置索引,无疑是一个不错的选择。

  另外,要慎用存储过程。虽然说存储过程可以帮助大家实现很多需求。但是,在万不得已的情况下,不要使用存储过程。而利用前台的应用程序来实现需求。这主要是因为在通常情况下,前台应用程序的执行效率往往比后台数据库存储过程要高的多。

  第五层:SQL 语句。

  若以上各个层面你都努力过,但是还不满足由此带来的效果的话,则还有最后一招。通过对SQL语句进行优化,也可以达到改善数据库性能的目的。

  虽然说SQL Server服务器自身就带有一个SQL语句优化器。他会对用户的SQL语句进行调整、优化,以达到一个比较好的执行效果。但是,据笔者的了解,这个最多只能够优化一些粗略的层面。或者说,80%的优化仍然需要数据库管理员的配合。要数据库管理员跟SQL优化器进行配合,才能够起到非常明显的作用。

  不过,SQL语句的调整对于普通数据库管理员来说,可能有一定的难度。除非受过专业的训练,一般很难对SQL语句进行优化。还好笔者受过这方面的专业训练,对这方面有比较深的认识。如在SQL语句中避免使用直接量。任何一个包含有直接量的SQL语句都不太可能被再次使用。我们数据库管理员要学会利用主机变量来代替直接量。不然,这些不可再用的查询语句将使得程序缓存被不可再用的SQL语句填满。这都是平时工作中的一些小习惯。

  总之,笔者认为,在数据库性能调优的时候,若能够遵循如上的顺序,必定可以让我们少走冤枉路,不花无用功。其实,数据库调优并没有我们想象的这么难。只要我们能够掌握其中的诀窍,数据库调优将可以手到擒来。


读后感:学习到的知识点如下:

1、对数据库的优化不仅仅是数据库还要看其网络环境以及机器的配置

2、对数据库的备份不能每次都是完全备份,要和差异备份结合使用【要了解并掌握这些备份的方法以及区别】

3、对数据库对象的优化,比如视图,我们尽量减少那些不必要的字段,宁可多增加一个视图

 

10.数据库恢复with move参数

     我们在数据库恢复的过程中,不一定都一定用到with move参数,只有在把数据还原到其他新的数据库的时候,并重新定义数据库文件地址 用到。

RESTORE DATABASE testdb FROM DISK = 'E:/20091124141351.bak'
WITH MOVE 'myData' TO 'f:/testdb.mdf',
MOVE 'myData_log' TO 'f:/testdb.ldf'

有个数据库备份文件为20091124141351.bak,那么现在想还原这个数据库为新的数据库并且数据文件存放到F盘下面并且主数据文件为testdb.mdf,次数据文件为testdb.ldf。

结果成功执行!打开F盘就能看到数据文件了。

 

 

11.浅谈简单恢复模式下的备份

      SQL Server数据库备份模式简单来说可以分为完整恢复模式下的备份与简单恢复模式下的备份。两种不同的备份模式各有特点。笔者认为数据库管理员要清楚这两种备份模式的差异,并结合企业的实际情况选择合适的备份模式。笔者在这篇文章中,主要是想和各位专家讨论下一下简单恢复模式下的备份方式的优缺点以及相关的管理要点。就当作抛砖引玉,期待与各位专家共同成长。
  一、 简单恢复模式的优点。

  简单恢复模式下的备份就如同这个名字一样,管理起来非常简单。因为在简单恢复模式下的备份,始终不会备份事务日志,故管理员来非常的方便。在简单恢复模式下,数据库系统会自动截断事务日志,以删除所有不活动的虚拟日志文件。截断通常发生在每个检查点之后。故不会对数据更新产生不利的影响。当数据库的更新频率比较高时,由于简单恢复模式下的备份方式始终不会备份事务日志,故其备份的效率会比较高。

  为此,笔者在数据库设计的时候,由于需要频繁的变更数据库的结构,需要创建新表或者调整相关参数。此时为了节省数据库备份的时间,笔者往往是采用简单恢复模式下的备份。当有重要的变更后,就即使对数据库进行备份。由于备份的时间间隔比较短,故不备份事务日志不会产生多大的负面影响。反而可以提高数据库的备份效率。

  二、 简单恢复模式的缺点。

  简单恢复模式下的备份最大的缺点就是可能导致最近数据备份之后所做的更新将会全部丢失。如现在有一个SQL Server数据库系统。在今天凌晨1点刚完成一个差异备份。而在上午企业上班的时候,企业用户通过前台客户端在系统中录入了不少的销售订单、采购订单等信息。可是不幸的是,在下午1点的时候数据库突然出现了故障。经检查是因为数据库的硬盘出现了不明原因的损坏。还有数据库管理员采用了异地备份。故马上采用了新硬盘并利用异地备份文件恢复相关的数据。但是由于采用了简单恢复模式下的备份,此时就遇到了一个文件。因为简单恢复下的备份方式不会备份事务日志。故在数据库恢复的时候,只能够恢复到凌晨1点的那个时刻的数据。上午上班员工录入的销售订单、采购订单等信息都无法恢复。此时员工只有重新建立这些信息。

  鱼与熊掌不能够兼得。简单恢复模式下的备份方式始终不用备份事务日志,故可以提供能比较快的备份速度。但是也正是因为如此,数据库在遇到故障时需要恢复的话,不能够恢复到故障的那个点上。为此数据库管理员需要权衡利弊,选择一个合适的备份方式。据笔者的个人经验而言,简单恢复模式并不适合用在生产系统上。因为对于大部分生产系统而言,丢失数据库的最新更改很可能用户是无法接受的。因为数据更改丢失很难找回,或者需要花费大量的时间补入。而数据库备份的时间,数据库管理元可以通过备份策略,把数据库备份作业放到晚上进行。此时用户使用数据库比较少,即使备份需要花费几个小时的时间,对用户的影响也不会很大。故对于生产系统而言,特别是更改比较频繁的生产系统,笔者是建议采用完整恢复模式,而不是这篇文章所讲述的简单恢复模式。

  三、 简单恢复模式的管理要点。

  从上面的分析中,大家可以看出简单恢复模式下的备份具有比较大的局限性。但是毕竟其管理方便、备份效率高,在一些特定的场合还是经常被数据库管理员所采用。现在的问题是,数据库管理员该采取一些怎么样的策略,把这个局限性降低到最低。笔者的做法是,提高差异备份的频率,对简单恢复模式下的备份方法进行补充,从而减少因为没有备份事务日志而造成的数据丢失的风险。

  差异备份基于数据的最新完整备份而延伸出来的一种备份策略。这称为差异的基准。差异基准是读、写数据的完整备份。差异备份仅包含自建立差异基准后发生更改的数据。通常,建立基准备份之后很短时间内执行的差异备份比完整备份的基准更小,备份速度也更快。因为差异备份只对上次备份以后的变更数据进行备份。故使用差异备份可以加快进行频繁备份的速度,从而降低数据丢失的风险。通常,一个差异基准会由若干个相继的差异备份使用。还原时,首先还原完整备份,然后再还原最新的差异备份。经过一段时间后,随着数据库的更新,包含在差异备份中的数据量会增加。这使得创建和还原备份的速度变慢。因此,必须重新创建一个完整备份,为另一系列的差异备份提供新的差异基准。可见完全备份与差异备份结合使用,可以有效的降低简单恢复模式下的数据丢失风险。

  通常情况下,差异备份所涵盖的数据文件与单个差异基准中所涵盖的文件相同。在简单恢复模式下,一个差异备份只能有一个差异基准。尝试使用多个基准会引发错误,并且备份操作将会失败。不过根据笔者的经验来看,一个差异备份只能有一个差异基准,基本上能够满足企业数据备份的需求。使用多基准差异备份反而会增加数据备份与恢复的难度,容易出错。故无论企业采用的是何种备份模式,笔者都建议用户尽量不要采用多基准差异备份。

可见差异备份与完整备份结合应用,并适当提高差异备份的频率,可以降低因为没有别分事务日志所造成的风险。但是这只能够起到降低的作用,而无法完全避免。如在上午10点时数据库做了一个差异备份。但是到下午1点是数据库出现了损坏。此时如果数据库管理员还原数据库的话,也只能够恢复到上午10点时(差异备份发生时)的数据。而恢复不到下午1点时故障发生时的数据。也就是说,上午十点到下午一点这几个小时中发生的数据变更将会丢失。可见简单恢复模式下的备份方案由于始终没备份事务日志,由此带来的数据损失风险无法避免。对于这一点,数据库管理元一定要铭记于心。

  创建 SQL Server 备份的目的是为了可以恢复已损坏的数据库。但是,备份和还原数据必须根据特定环境进行自定义,并且必须使用可用资源。故如果结合数据库资源来考虑,并不能够说简单恢复模式下的备份策略不好。如果企业比较看重备份的速率,而对于数据丢失的风险在一定程度之内可以忍受的话,那么简单恢复模式下的备份策略还是比较适合这种情况的。

  四、 简单恢复模式下的备份总结

  简单恢复模式下的备份跟完整备份模式或者大容量日志备份模式的差异主要体现在事务日志备份上。简单恢复模式下的备份始终不会对事务日志进行备份,故最新备份之后的更改将不受保护。在发生数据库故障后,这些更改用户必须手工的重新做一遍。即利用备份文件只能够恢复到备份的结尾,而不能够恢复到数据库故障的时点上。而简单完整备份模式下的最大优点是数据库系统会回收日志空间以减少硬盘空间的需求,或者说数据库管理元不需要再管理事务日志空间。同时其进行数据库备份的时间也会大大缩短。

 

12.SQL2000异地备份数据

    /*
第一步:
在SQL server中做映射网络盘
192.169.116.2为远程备份机
administrator为远程备份机登录用户名
111111为远程机器密码
bak为完全共享的文件夹
注意:(Z:后面要有一个空格)*/
exec master..xp_cmdshell 'net use z: //192.169.116.2/bak "111111" /user:192.169.116.2/administrator'

/*第二步:进行删除前四日的数据库备份文件*/
declare @myBackupName varchar(200)
set @myBackupName = 'del z:/fst_center' + convert(varchar(10),GETDATE()-4,112) + '.dat'
exec master..xp_cmdshell @myBackupName

/*第三步:进行当天的数据库备份*/
declare @MyDataName varchar(200)
set @MyDataName='z:/fst_center' + convert(varchar(10),GETDATE(),112) + '.dat'
backup database fst_center1 to disk=@MyDataName

/*第四步:备份完成后删除映射*/
exec master..xp_cmdshell 'net use z: /delete'


语法:

此命令的语法是:
NULL
NET USE
[devicename | *] [//computername/sharename[/volume] [password | *]]
[/USER:[domainname/]username]
[/USER:[dotted domain name/]username]
[/USER:[username@dotted domain name]
[/SMARTCARD]
[/SAVECRED]
[[/DELETE] | [/PERSISTENT:{YES | NO}]]
NULL
NET USE {devicename | *} [password | *] /HOME
NULL
NET USE [/PERSISTENT:{YES | NO}]
NULL
NULL

exec exec master..xp_cmdshell'net use //192.10.10.22/D$ "1234" /USER:192.10.10.22/administrator' master..xp_cmdshell'net use //192.10.10.22/D$ "1234" /USER:192.10.10.22/administrator'

 

13.Sql 2005数据库的sa密码忘记了怎么办?

     sp_password Null,'123,'sa'
     把sa的密码设为"123"

     执行成功后有"Command(s) completed successfully." OK!

 

14.数据库日志文件很大时清空日志

      DUMP TRANSACTION 库名 WITH NO_LOG

 

15.Sql2005内部函数/存储过程/以及数据库角色

 

     获得当前ID的最顶级父类ID

============================================= 
-- Description: <获得当前ID的最顶级ID>
-- =============================================
CREATE FUNCTION getParentID(@ID int)
RETURNS int
AS
BEGIN
declare @BackID int
declare @TempTab table(TempID int)
insert into @TempTab select T_ID from T_Type where T_ID=@ID
while @@rowcount<>0
begin
insert into @TempTab
select T.T_Parent from T_Type T inner Join @TempTab A on T.T_ID=A.TempID where T.T_Parent<>0 and T.T_Parent not in (select TempID from @TempTab)
end
set @BackID=(Select Top 1 TempID from @TempTab order by TempID asc)
return @BackID
END
GO

select dbo.getParentID(29)--调用查看

 

 

       获得当前id所有的下级信息(自定义函数)

       SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE FUNCTION  [dbo].[F_AreaId](@ID VARCHAR(50))

RETURNS TABLE

AS

RETURN(WITH Temp_Area(id,AreName,ParentID)

AS (SELECT id,AreName,ParentID FROM Easy_Area WHERE  ID = @ID AND AreStatus = 1

UNION ALL 

SELECT a.id,a.AreName,a.ParentID FROM Easy_Area a INNER JOIN Temp_Area t ON(A.ParentID = t.id)

)

SELECT id,AreName,ParentID FROM Temp_Area

);

      /*日期函数*/
DATEADD ( datepart , number, date )
--在向指定日期加上一段时间的基础上,返回新的 datetime 值。
DATEDIFF ( datepart , startdate , enddate )
--返回跨两个指定日期的日期和时间边界数。
DATENAME ( datepart , date )
--返回代表指定日期的指定日期部分的字符串。
DATEPART ( datepart , date )
--返回代表指定日期的指定日期部分的整数。
DAY ( date )
--返回代表指定日期的天的日期部分的整数。
GETDATE ( )
--按 datetime 值的 Microsoft? SQL Server? 标准内部格式返回当前系统日期和时间。
GETUTCDATE()
--返回表示当前 UTC 时间(世界时间座标或格林尼治标准时间)的 datetime 值。
--当前的 UTC 时间得自当前的本地时间和运行 SQL Server 的计算机操作系统中的时区设置。
MONTH ( date )
--返回代表指定日期月份的整数。
YEAR ( date )
--返回表示指定日期中的年份的整数。

Sql Server中的日期与时间函数
1. 当前系统日期、时间
select getdate()

2. dateadd 在向指定日期加上一段时间的基础上,返回新的 datetime 值
例如:向日期加上2天
select dateadd(day,2,'2004-10-15') --返回:2004-10-17 00:00:00.000

3. datediff 返回跨两个指定日期的日期和时间边界数。
select datediff(day,'2004-09-01','2004-09-18') --返回:17

4. datepart 返回代表指定日期的指定日期部分的整数。
SELECT DATEPART(month, '2004-10-15') --返回 10

5. datename 返回代表指定日期的指定日期部分的字符串
SELECT datename(weekday, '2004-10-15') --返回:星期五

6. day(), month(),year() --可以与datepart对照一下

select 当前日期=convert(varchar(10),getdate(),120)
,当前时间=convert(varchar(8),getdate(),114)

select datename(dw,'2004-10-15')

select 本年第多少周=datename(week,'2004-10-15')
,今天是周几=datename(weekday,'2004-10-15')

函数 参数/功能
GetDate( ) 返回系统目前的日期与时间
DateDiff (interval,date1,date2) 以interval 指定的方式,返回date2 与date1两个日期之间的差值 date2-date1
DateAdd (interval,number,date) 以interval指定的方式,加上number之后的日期
DatePart (interval,date) 返回日期date中,interval指定部分所对应的整数值
DateName (interval,date) 返回日期date中,interval指定部分所对应的字符串名称


参数 interval的设定值如下:

值 缩 写(Sql Server) (Access 和 ASP) 说明
Year Yy yyyy 年 1753 ~ 9999
Quarter Qq q 季 1 ~ 4
Month Mm m 月1 ~ 12
Day of year Dy y 一年的日数,一年中的第几日 1-366
Day Dd d 日,1-31
Weekday Dw w 一周的日数,一周中的第几日 1-7
Week Wk ww 周,一年中的第几周 0 ~ 51
Hour Hh h 时0 ~ 23
Minute Mi n 分钟0 ~ 59
Second Ss s 秒 0 ~ 59
Millisecond Ms - 毫秒 0 ~ 999


access 和 asp 中用date()和now()取得系统日期时间;其中DateDiff,DateAdd,DatePart也同是能用于Access和asp中,这些函数的用法也类似

举例:
1.GetDate() 用于sql server :select GetDate()

2.DateDiff('s','2005-07-20','2005-7-25 22:56:32')返回值为 514592 秒
DateDiff('d','2005-07-20','2005-7-25 22:56:32')返回值为 5 天

3.DatePart('w','2005-7-25 22:56:32')返回值为 2 即星期一(周日为1,周六为7)
DatePart('d','2005-7-25 22:56:32')返回值为 25即25号
DatePart('y','2005-7-25 22:56:32')返回值为 206即这一年中第206天
DatePart('yyyy','2005-7-25 22:56:32')返回值为 2005即2005年


--------------------------------------------------------------------------
/*字符串处理函数*/
LCASE( )
LOWER( )
--将字符串转换为小写字母
LTRIM( )
--删除字符串前面的空格
SUBSTRING( )
--从字符串中提取一个或多个字符
UCASE( )
UPPER( )
--将字符串转换为大写字母
ROUND( )
--将数字按指定的小数位数四舍五入
FLOOR( )
--将数字向下四舍五入为最接近(最小)的整数
CEILING( )
--将数字向上四舍五入为最接近的整数
DATALENGTH( )
--返回指定的表达式所用的字节数
--------------------------------------------------------------------------
USER( )
USER_NAME( )
--返回当前用户名
CONVERT( )
--将数据从一种类型转换为另一种类型。
SOUNDEX( )
--为可创建"近似"搜索的指定表达式返回 Soundex 代码。
STR( )
--将数字数据转换为字符串,以便可以用文本运算符对其进行处理。
/*全局变量*/
@@CONNECTIONS
--服务器上次启动以来创建的连接数
@@CPU_BUSY
--自 SQL Server 启动至今,系统持续运行的毫秒数。
@@CURSOR_ROWS
--最近打开的游标中的行数
@@DATEFIRST
--SET DATEFIRST 参数的当前值,该参数用于设置一个星期的第一天为哪一天。
@@ERROR
--最后一个 T-SQL 错误的错误号
@@FETCH_STATUS
--如果最后一次提取的状态为成功状态,则为 0。如果出错,则为 -1
@@IDENTITY
--最后一次插入的标识值
@@LANGUAGE
--当前使用的语言的名称
@@MAX_CONNECTIONS
--可以创建的同时连接的最大数
@@ROWCOUNT
--受上一个 SQL 语句影响的行数
@@SERVERNAME
--本地服务器的名称
@@SERVICENAME
--该计算机上的 SQL 服务的名称
@@TIMETICKS
--当前计算机上每指令周期的微秒数
@@TRANSCOUNT
--当前连接打开的事务数
@@VERSION
--SQL Server 的版本信息
-----------------------------------------------------------------------
/*存储过程*/
sp_databases --列出服务器上的所有数据库
sp_server_info --列出服务器信息,如字符集,版本和排列顺序
sp_stored_procedures--列出当前环境中的所有存储过程
sp_tables --列出当前环境中所有可以查询的对象
sp_start_job --立即启动自动化任务
sp_stop_job --停止正在执行的自动化任务
sp_password --添加或修改登录帐户的密码
sp_configure --显示(不带选项)或更改(带选项)当前服务器的全局配置设置
sp_help --返回表的列名,数据类型,约束类型等
sp_helptext --显示规则,默认值,未加密的存储过程,用户定义的函数,
--触发器或视图的实际文本
sp_helpfile --查看当前数据库信息
sp_dboption --显示或更改数据库选项
sp_detach_db --分离数据库
sp_attach_db --附加数据库
sp_addumpdevice --添加设备
sp_dropdevice --删除设备
sp_pkeys --查看主键
sp_fkeys --查看外键
sp_helpdb --查看指定数据库相关文件信息
sp_addtype --自建数据类型
sp_droptype --删除自建数据类型
sp_rename --重新命名数据库
sp_executesql --执行SQL语句
sp_addlogin --添加登陆
sp_droplogin --删除登录
sp_grantdbaccess --把用户映射到登录,即添加一个数据库安全帐户并授予塔访问权限
sp_revokedbaccess--撤销用户的数据访问权,即从数据库中删除一个安全帐户
sp_addrole --添加角色
sp_addrolemember --向角色中添加成员,使其成为数据库角色的成员
sp_addsrvrolemember--修改登录使其成为固定服务器角色的成员
sp_grantlogin --允许使用组帐户或系统用户使用Windows身份验证连接到SQL
sp_defaultdb --修改一个登录的默认数据库
sp_helpindex --用于查看表的索引
sp_cursoropen --定义与游标和游标选项相关的SQL语句,然后生成游标
sp_cursorfetch --从游标中提取一行或多行
sp_cursorclose --关闭并释放游标
sp_cursoroption --设置各种游标选项
sp_cursor --用于请求定位更新
sp_cursorprepare --把与游标有关的T-SQL语句或批处理编译成执行计划,但并不创建游标
sp_cursorexecute --从由sp_cursorprepare创建的执行计划中创建并填充游标
sp_cursorunprepare --废弃由sp_cursorprepare生成的执行计划
sp_settriggerorder --指定第一个或最后一个激发的、与表关联的 AFTER 触发器。在第一个
--和最后一个触发器之间激发的 AFTER 触发器将按未定义的顺序执行
--------------------------------------------------------------------------------
/*服务器角色*/
sysadmin
--在 SQL Server 中进行任何活动。该角色的权限跨越所有其它固定服务器角色。
serveradmin
--配置服务器范围的设置。
setupadmin
--添加和删除链接服务器,并执行某些系统存储过程(如 sp_serveroption)。
securityadmin
--管理服务器登录。
processadmin
--管理在 SQL Server 实例中运行的进程。
dbcreator
--创建和改变数据库。
diskadmin
--管理磁盘文件。
bulkadmin
--执行 BULK INSERT 语句。
/*数据库角色*/
public
public 角色
--public 角色是一个特殊的数据库角色,每个数据库用户都属于它。public 角色:
--捕获数据库中用户的所有默认权限。
--无法将用户、组或角色指派给它,因为默认情况下它们即属于该角色。
--含在每个数据库中,包括 master、msdb、tempdb、model 和所有用户数据库。
--无法除去。
db_owner
--进行所有数据库角色的活动,以及数据库中的其它维护和配置活动。
--该角色的权限跨越所有其它固定数据库角色。
db_accessadmin
--在数据库中添加或删除 Windows NT 4.0 或 Windows 2000 组和用户以及 SQL Server 用户。
db_datareader
--查看来自数据库中所有用户表的全部数据。
db_datawriter
--添加、更改或删除来自数据库中所有用户表的数据
db_ddladmin
--添加、修改或除去数据库中的对象(运行所有 DDL)
db_securityadmin
--管理 SQL Server 2000 数据库角色的角色和成员,并管理数据库中的语句和对象权限
db_backupoperator
--有备份数据库的权限
db_denydatareader
--拒绝选择数据库数据的权限
db_denydatawriter
--拒绝更改数据库数据的权限

 

    由于登录失败无法启动sqlserver代理服务的解决办法

    以前一直是代理备份数据库的。打开SSMS才知道代理服务停止了,点击启动服务出现如下错误:

错误代码:1069, 由于登录失败无法启动服务。

后来查了一些资料才解决了。原来是我以前测试的时候建立了一个用户,现在代理启动是以那个用户启动的,我现在以admin管理员的身份当然无法启动服务。问题找到了,就好解决了。

打开服务控制管理器(在运行中,输入services.msc),找到sqlserver代理服务-SQL Server Agent (WON-这里是你的实例名称)--属性--登录--浏览-找到你想运行的用户即可。

 

   插入数据后如何获得最大记录编号

      我们都知道可以采用seletc @@identity的语句来实现,并且使用存储过程的方式输出参数,但是,这绝对是正确的吗?我的答案是不一定!

我在网络上也搜索了这方面的知识点,并且结合自己的实践得出如下结论:
1、当表上存在触发器(插入数据触发)
2、非一个链接操作数据

具体是怎么回事呢?下面来详细的介绍。

在说明之前先创建一个测试表(存在自动编号的列),语句如下:
create table Test_Identity(intID int identity(1,1) not null,TestName varchar(50) null)

insert into Test_Identity default values
seletc @@identity
结果为1
insert into Test_Identity default values
seletc scope_identity()
结果为2

结论都是正确的,好,那么我们开始测试下面的情况

一、先说触发器

创建另外一个表,保存触发器操作的数据
create table Test_Trigger(intID int identity(1,1) not null,Triggname varchar(50) null)

在表Test_Identity上穿件触发器
create trigger _Trigger on dbo.Test_Identity for insert as
set nocount on
insert into Test_Trigger(Triggname) select TestName from inserted

开始测试数据
insert into Test_Identity default values
seletc @@identity

结果为1,实际上结果应该为3才是正确的

insert into Test_Identity default values
seletc scope_identity()
结果为4,结论正确

二、当前非一个链接操作
由于没办法截图,其实想下就知道,采用seletc @@identity方式肯定不行,返回的结果有可能是错误的。

 

    Sql语句从右开始查找字符串

            我们一般使用substring()对字符串进行截取,但是如果想从右侧进行截取的话,可以对字段反转过来

select top 10 REVERSE(substring(REVERSE(FileUrl),1,4)) from T_Table

REVERSE(FileUrl)--反转字段

substring(REVERSE(FileUrl),1,4)--截取4位

REVERSE(substring(REVERSE(FileUrl),1,4)) --再次反转

最后就是我们要用到的数据了

比如:UpFiles/200803_5003501060120080300440100444152.doc

最后得的结果是 .doc

 

   Sql语句中字符串和日期之间的转换

     我们经常对日期进行转换,一般是对日期进行转换成字符串然后再对字符串进行格式化操作。

比如:update T_Gknb set T_Date=replace(convert(varchar(14),CreateTime,111),'/','-')

convert(varchar(14),CreateTime,111)--日期转化为14位的字符串

replace(convert(varchar(14),CreateTime,111),'/','-')--替换字符串中的 / 为 -

日期转换的规则如下:

convert(datatype,expression,[style])

style参数默认显示的是年度2位,比如--yy(08,09)

如果想设置4位年度显示方式,请再加上100,即

2位--4位--输入输出方式

0 100 mon dd yyyy hh:miAM(或PM)
1 101 mm/dd/yy
2 102 yymmdd
3 103 dd/mm/yy
4 104 ddmmyy
5 105 ddmmyy
6 106 dd mon yy
7 107 mon dd,yy
8 108 hh:mm:ss
9 109 mon dd yyyy hh:mi:ss:mmmmAM(或PM)
10 110 mmddyy
11 111 yy/mm/dd
12 112 yymmdd
13 113 dd mon yyyy hh:mi:ss:mmm(24小时制)
14 114 hh:mi:ss:mmm(24小时制)
20 120 yyyymmdd hh:mi:ss(24小时制)
21 121 yyyymmdd hh:mi:ss:mmm(24小时制)

举例:

select CONVERT(varchar, getdate(), 120 )
2004-09-12 11:06:08

select replace(replace(replace(CONVERT(varchar, getdate(), 120 ),'-',''),' ',''),':','')
20040912110608

select CONVERT(varchar(12) , getdate(), 111 )
2004/09/12

select CONVERT(varchar(12) , getdate(), 112 )
20040912

select CONVERT(varchar(12) , getdate(), 102 )
2004.09.12

select CONVERT(varchar(12) , getdate(), 101 )
09/12/2004

select CONVERT(varchar(12) , getdate(), 103 )
12/09/2004

select CONVERT(varchar(12) , getdate(), 104 )
12.09.2004

select CONVERT(varchar(12) , getdate(), 105 )
12-09-2004

select CONVERT(varchar(12) , getdate(), 106 )
12 09 2004

select CONVERT(varchar(12) , getdate(), 107 )
09 12, 2004

select CONVERT(varchar(12) , getdate(), 108 )
11:06:08

select CONVERT(varchar(12) , getdate(), 109 )
09 12 2004 1

select CONVERT(varchar(12) , getdate(), 110 )
09-12-2004

select CONVERT(varchar(12) , getdate(), 113 )
12 09 2004 1

select CONVERT(varchar(12) , getdate(), 114 )
11:06:08.177

 

关于事务阻塞显示数据问题

      两个知识点
1、ReadPast--相当于历史数据
2、NoLock--未锁定的数据

不知道理解的是否正确
我亲自测试了这些方法,先执行事务形成阻塞,然后查询

begin transaction

insert into Tab values('12121')

--先执行事务,并且事务不关闭


select * from Tab --由于阻塞无法显示
select * from Tab(ReadPast)--能显示数据,只是是旧的数据
select * from Tab(NoLock)--能显示数据,并且事务执行成功的数据也在里面

如果我们在程序中加以应用,应该对系统有很大帮助

 

数据库锁定信息查询

     如果想查询数据库系统为什么这么慢,可以先看下是否有进程死锁的现象。

exec sp_lock可以查询系统进程信息列表

现在对每个字段进行详细的解释:

spid:系统进程标识码。如果你想知道哪些用户和此spid相连,那么你可以通过exec sp_who spid进行查询相关信息:exec sp_who 54

 

dbid:锁定所发生的数据库。你可以通过主数据库master中的sysdatabases中找到对应的信息(dbid)

select * from sysdatabases 


objid:锁定对象。你可在sysobjects表中查询到相关的信息(id)。select * from sysobjects

在执行查询的时候可能每次都不一样,那是因为有的锁定已解除,或者新的锁定添加了进来。如果你发现一个或者多个进程spID,一直存在,那么这个进程就可能是处理比较大的过程了。

如果想知道当前占用资源的进程的语句或者存储过程在执行。可以通过DBCC INPUTBUFFER(SPID)查看。

这个DBCC命令将返回正在EventInfo字段中运行的语句的相关信息。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章