SQL Server是一门非常专业的学问,涉及方方面面的知识。想成就一名SQL Server高手,需要一定的数据库理论知识和多年的实践锻炼。
在开始SQL Server学习之前,我们必须首先确定自己的定位,才能有的放矢,事半功倍。
如果你希望成为“数据库设计人员”,你应该学会从整体上把握SQL Server、掌握数据库理论知识、学习数据库系统建模;
如果你希望成为“数据库开发人员”,你应该好好学习T-SQL 编程技术;
如果你希望成为“数据库管理员”,你应该把精力放在SQL Sever性能调控和数据库系统维护上;
如果你希望成为“数据分析员”,你应该着重注意SQL Server关于OLAP方面的知识。
SQL Server 2000由两个部分组成:服务器组件和客户端工具。
1.SQL Server的服务器组件是以Windows服务(Windows Services)方式运行的。一般认为SQL Server包含四种Windows服务(这里我们关注OLTP、暂时不考虑 OLAP),分别是:MSSqlServer、DTC(Distributed Transaction Coordinator)、SQLServerAgent、Search Service。
MSSqlServer 是最常用的服务,一般的数据库功能都是由它提供的,例如文件管理、查询处理、数据存储等;
DTC是分布式事务协调器,支持跨越两个或多个服务器的更新操作来保证事务的完整性;
SQLServerAgent负责SQL Server自动化工作,如需要SQL Server 在指定时间执行某一个存储过程,就需用到这个服务;Search Service是全文查询服务,负责全文检索方面的工作。
2.服务器组件是引擎,客户端工具是用户界面,两者是相辅相成的。
让我们看看SQL Server 2000的客户端工具到底有哪些──企业管理器、查询分析器、事件探查器、服务管理器、客户端网络实用工具、服务器网络实用工具、导入和导出数据(DTS)等等。
服务器组件与客户端工具功能上是配套的,客户端工具需要用最简单的形式表达最丰富的服务器组件的功能;服务器组件和客户端工具物理上是离散的,说句大白话:它们不是同一个程序!客户端工具要与服务器组件连通,需要一些用于通讯的动态链接库,SQL Server 2000的通讯库支持多种网络协议,例如TCP/IP、命名管道等。
打开“企业管理器”,展开数据库本机SQL Server实例节点的数据库项目,可以发现SQL Server已经自动安装了六个数据库。
●master数据库记录SQL Server系统的所有系统级别信息。
●tempdb数据库保存所有的临时表和临时存储过程。
●model数据库是为用户创建数据库提供的模板。
●msdb数据库供SQL Server代理程序调度警报和作业以及记录各种操作。
●northwind和pubs是示例数据库,以后我们要经常利用它们做演示。
除了northwind和 pubs之外,其他四个数据库都是由SQL Server自行维护的,一般不需要用户干预。
SQL主要分为三个部分:数据定义语言(DDL)、数据操纵语言(DML)和数据控制语言(DCL)。
数据定义语言包括数据库(Database)、数据表(Table)、视图(View)、索引(Index)、存储过程和触发器等的创建和删除操作
CHAR(x):固定长字符串,其中x表示包含字符的个数,如果要保存的数据不够x个字符,将自动补以空格。
VARCHAR(x):可变长字符串,x的含义同上。
INTEGER:整型数,不保存小数点右边的数字。
DECIMAL(x,y)或NUMERIC(x,y):实数,其中x是该列数据(十进制)的最大数字位数,y表示小数点右边允许出现的数字的最大位数,如某字段定义为DECIMAL(5,2),则它的最大值是999.99。
DATE或DATETIME:日期列表,它的具体格式与数据库系统有关。
BOOLEAN:逻辑值,只有两个值,TRUE和FALSE。
把业务逻辑封装在存储过程中起码有如下好处:
●使反映业务逻辑的代码模块化、集中化,使维护管理工作更简易;
●允许不同的客户端应用程序访问存储过程,共享业务逻辑;
●在存储过程执行之前SQL Server会对它进行“伪编译”,执行效率高;
●存储过程一旦运行,就被装入高速缓冲区,以备下次调用,使用存储过程可以减少代码从磁盘装载的过程,提高服务器的工作效率;
●客户端调用存储过程只需要极少的语句,能够有效地降低网络流量;
●在安全方面,存储过程的优势体现在以下两个方面:其一,存储过程是对付来自Web的“SQL注入式”攻击的有效手段;其二,SQL Server允许在存储过程上设定执行权限。
EXEC @COUNT=SalesByCategory_TEST 'Condi ments',@YEAR,@MSG OUTPUT
INSERT INTO #TEMP (ProductName ,TotalPur chase) EXEC SalesByCategory 'Condiments',DE FAULT,''
我们揭示了触发器的内幕:INSERTED 和DELETED虚拟表。当用INSERT 语句插入数据时,INSERTED虚拟表保存了新插入的数据集;当用DELETE语句删除数据时,DELETED虚拟表保存了被删除的数据集;当用UPDATE语句修改数据时(读者可以把UPDATE理解成先DELETE再INSERT的操作),DELETED虚拟表中保存了被更改前的数据集,INSERTED虚拟表中保存了更改后的数据集。
很难通过操作视图更新基表。例如我们建立了分区视图(用UNION连接),然后执行INSERT语句往视图中插入数据,SQL Server 会弹出“派生表 'XXX' 不可更新,因为其定义中包含 UNION 运算符”的出错提示,这是因为SQL Server 不知道应该把数据写入哪张基表中。不过,另一类触发器──INSTEAD OF触发器,就可以解决这个问题。INSTEAD OF触发器的运行原理与AFTER 触发器大相径庭:
●INSTEAD OF触发器可以绑定在表和视图上(一般在视图上),AFTER触发器只能绑定在表上。
●和AFTER触发器一样,INSTEAD OF触发器由INSERT、UPDATE和DELETE三个操作触发;一个表可以绑定多个AFTER INSERT、AFTER UPDATE、AFTER DELETE触发器,而在视图(或表)上每种类型的INSTEAD OF触发器只能有一个。
●当在视图(或表)上执行INSERT(或UPDATE、DELETE)时,如果SQL Server 发现在视图(或表)上有相应的INSTEAD OF触发器,SQL Server就会取消对视图(或表)的实际操作,转为执行INSTEAD OF触发器。
事务是一系列在它们的结果变成永久性之前必须全部成功结束的事件。事务是一个逻辑工作单元,由一条或多条SQL语句组成,这些语句被当作一个整体看待──要么全执行,要么全不执行。
BEGIN TRAN:启动事务,它告诉SQL Server一个事务开始了,要求系统按照ACID的标准来处理事务中的语句。
COMMIT:提交事务,它告诉SQL Server事务执行成功,可以把BEGIN TRAN以后的所有SQL 语句造成的数据变动永久写入磁盘。
ROLLBACK:撤消事务,它告诉SQL Server把BEGIN TRAN以后的所有SQL 语句造成的数据变动撤消,就像它们从来没有执行过一样
DECLARE @ErrorCode int
SELECT @ErrorCode=0
--启动一个事务
BEGIN TRAN
***
IF @ErrorCode=0
BEGIN
COMMIT
PRINT '提交事务'
END
ELSE
BEGIN
ROLLBACK
PRINT '撤消事务'
END
大多数数据库系统都需要为多个用户提供服务,于是就出现了这样一种情况:多人同一时刻对同一数据进行读写,这就是所谓的“并发”。可以想象,如果对并发不进行有效的控制,数据库随时都可能处于混乱状态,这种由并发带来的问题称作“并发冲突”。
SQL Server通过锁来处理并发冲突问题,它的基本思想是:在一个事务中锁定需要修改的数据表,这时即使有其他并发事务执行,由于数据表已经被锁定,也不可能发生多个事务在同一时刻对同一数据进行读写的情况,从而避免了并发冲突。
不难看出,锁虽然能够解决并发冲突问题,但是使用锁的代价是高昂的:第一,锁必然导致系统并发能力降低,在繁忙的系统中,过多的锁必然导致系统效率低下,让用户无法忍受;第二,人工加锁、解锁的过程是痛苦的,对开发人员要求很高。
三类冲突问题分别是“脏读”、“不可重复读”和“幻影读”。
四种事务隔离级别分别是“读未提交”(READ UNCOMMITTED)、“读已提交”(READ COMMITTED)、“可重复读”(RE PEATABLE READ)和“可串行化”(SERI ALIZABLE)。这四种隔离级别也可以看做是四种不同的锁方案。总地来说,“读未提交”是一种无锁的状态,不能对付任何并发冲突;“读已提交”可以对付“脏读”;“可重复读”可以对付“脏读”和“不可重复读”这两种并发冲突;“可串行化”可以对付所有三种并发冲突。
当表名 中含有空格,需给表明加""
SELECT SUM(UnitPrice * Quantity) FROM "Order De tails" WHERE ProductID=1
1.支持通配符的CHARINDEX和LIKE关键字
比如查找用户名包含有“c”的所有用户,可以用
SELECT * FROM table1 WHERE us er_name LIKE “%c%”
下面是完成上面功能的另一种写法:
SELECT * FROM table1 WHERE CHARINDEX (“c”user_name)>0
SELECT * FROM table1 WHERE CHARINDEX (“%”,user_name)>0
2.少使用“*”
3.尽量不要在WHERE子句中对字段使用函数或参与表达式来计算
这样会导致无法使用索引进行全表扫描。
4.尽量少使用NOT
5.IN和EXISTS
EXISTS要远比IN的效率高,里面关系到full table scan和range scan。同时应尽可能使用NOT EXISTS来代替NOT IN
6.慎用游标
在某些必须使用游标的场合,可考虑将符合条件的数据行转入临时表中,再对临时表定义游标进行操作,这样可使性能得到明显提高。