• 数据库表关系:1对1,1对多,多对多(两个表,如果两个方向都是1对多,它们就是多对多关系,多对多有一个中间表。如:1个人可收藏多个商品,1个商品可被多个人所收藏)。中间表命名规范:“R_”(R–关系)开头,两个表与中间表都是1对多关系。
  • CRUD是增加(Create)、查询(Retrieve)、更新(Update)和删除(Delete)单词的首字母。
  • SQL server共有5个系统DB:master(sql server系统所有系统级信息。如登陆账号、系统配置、其他数据库的存在和位置等);msdb(代理计划警报和作业、邮件等);model(创建所有数据库的模板);tempdb(保存临时对象和中间结果,每次启动重新创建);Resource(只读的,存放系统对象的物理文件,但逻辑上显示每个DB的sys架构中。)
  • 数据库的分离与脱机,二者差不多,操作后你可以移动数据库文件,但是后者操作后在数据库管理器里能看到DB,只是不能用。
  • 一个数据库最多可创建32767个数据库文件,最多可有20亿张表,一个表最多可1024列,每行最大字节数为8060。
  • 收缩数据库:若往表里插入大量数据,然后delete这些数据,发现数据库文件大小没相应缩小。所以要收缩数据库。
  • 数据类型:

    • 存图片,可用binary(字节)类型、image类型(存字节,没大小限制,所以也可存文档)。
    • char(2) 存中文占2字节,英文或数字占1字节。nchar(2) 表示不论中文、英文、数字等,每个字符都占2字节。浪费磁盘空间!!!! 不带n的最长可为8000,有n的最长是4000。带n的一般存中文或双字节字符。
    • char、varchar的var表示可变长度,如varchar(3),仅存“ab”不会用空格补齐。前者是固定长度,如char(3),仅存’a’的话,后面用2两个空格补充。
    • 当数据库的“排序规则”不是简体中文(即非中文)要存中文则必须是用带“n”的类型,不用的话存入的是乱码!
    • insert语句形如“insert into tblName values(N’张三’,50)”——加‘N’目的是防止中文乱码,英文则可不加。所以,写sql时含中文的一定要加‘N’
    • text、ntext,不推荐用,sql2005以前用的多。当长度8000不够用,则用varchar(max)(表示字段可存4GB内容,sql2005后才有)
    • datetime、datetime2,后者能存入更高精度的时间(精度主要反映在毫秒、飞秒)
  • 一条信息在数据库中是不允许出现两次,我们是通过PK(主键)来实现避免重复的,一个表只能有一个PK(SQL Server是钥匙图标表示)。因为SQL server默认会给它建索引,入库的数据保存在磁盘中顺序是按PK排序后的顺序保存。 可设置为PK的列规则:“业务主键(如身份证号、工号)、逻辑主键(id列自+1)”,推荐用后者,前者发生重复不可避免。不推荐使用“复合主键”,一个列如果符合“单列+入库后值不变+数字+唯一”则优先设置为PK,标识列即自+1的列刚好全达标,也是大家喜欢用标识列来做主键原因)。
  • IDENTITY(1,1):设置标识列(列值自增1)。 PRIMARY KEY:设置主键列
  • 主键和标识列区别:主键是为了每条数据的唯一,而简单有效的手段是设置id标识列为主键。一个表的主键可以是多列构成(联合主键),标识列只有一列。标识列必须为不带小数的数值类型,主键列可是任意类型。
  • SQL是结构化查询语句,是关系型数据库的标准语言。微软和Sybase对其扩展成了T-SQL(作业SQL)。后者是在1986年发布,且是首个商用关系型数据库公司。后来授权给微软,后者支持unix和Linux。MariaDB数据库管理系统是MySQL的一个分支,其是由MySQL的创始人Michael Widenius主导开发。
  • DDL——数据定义语言,建库/表,删/改表。DML(数据操作语言)——select、insert、delete、update。DCL(数据库控制语言)——GRANT授权、Revoke取消授权。
  • 数据冗余
    • 冗余危害:浪费存储空间、“更新、删除”很难做到干净。
    • 冗余好处:查询快,SQL编写简单
    • 减少冗余办法:越高的范式冗余越小。最直观办法是把表中数据放到多个表中。怎么关联多个表?用PK和FK进行关联。
  • 有外键的表叫“外键表”,主键被引用的表叫“主键表”。
  • 往id列已经设置为“PK且identity(1,1)”的表中插入值的方法:
 SET IDENTITY_INSERT tblName ON --开启手动插入INSERT INTO tblName ...--insert语句要含id值,但是不能重复!!(如果tblName就1条数据,id值500,则下一个id为501)SET IDENTITY_INSERT tblName OFF--关闭手动插入
  • where后面可以有的逻辑运算符:or 、and、not、in(会被编译成or)、=、>、>=、<、<=、<>(或!=)
  • Truncate TABLE tblName–直接清空表,比“delete from tblName”速度快。清空后的表id恢复从1开始。执行时不触发delete触发器。有外键约束时,不能truncate,而delete可能失败,如要删的对象外键在主键表没有,才能执行成功。
  • 约束常见6种:不为空约束、主键约束(PK,金色钥匙图标)、默认约束、
    外键约束(要插入的外键如果不存在就会异常。外键表右键“关系”->“添加”->…删除规则:级联–删主表是部门表数据,人员信息外键表相关数据也会删掉;删外键表一条就是一条不会级联)、唯一约束(如邮箱或手机号列必须唯一,右键“索引/键”->添加类型是唯一键,并选相应列,蓝色钥匙图标)、检查约束(年龄列实际肯定不会1000,故可加“age>0 AND age<=150”)
  • Select TOP 30 PERCENT * from tbl --符合相应占比(返回小数则向上取整)数据
  • 聚合函数:顾名思义就是多条变一条。分组后才能用它,一般用它来统计数据。常用:max、MIN、COUNT、AVG、SUM,没有group by则视为一组(select语句中出现的列,要么放到group by后面用于分组,要么在sum等聚合函数里用于统计值,只会出现在这两个地方)。聚合函数,对null值不计算。若对同一表count(address)和count(*)则,前者有null值时返回值可能比后者小。avg也是不统计空值。
SELECT 平均年龄=(SELECT SUM(age) FROM tlb1)/(SELECT COUNT(age) FROM tlb1)--结果是int型,如果想让结果是小数,则sum值乘以1.0即可.
SELECT Emp_No,SUM(1) a FROM PR_People Where AssessID='225' Group By Emp_No having sum(1)=1 ORDER BY Emp_No
- SELECT * FROM Base_Organize WHERE OrderID IN(1,2,3) --OR 等同于in ,但是如果OrderId是有序的则“OrderID>=1 AND OrderID<=3”(其等同于“between 1 and 3”)更高效
  • Where、Having“过滤”功能区别详解:行级过滤,用where。对分组后的结果集过滤,用having。具体:where语句的执行顺序在分组之前,并且where只能过滤行,不能过滤分组(where中不能使用聚合函数)。having执行在分组之后,对group分组的结果集进行过滤,having子句中可以直接使用聚合函数。

  • Null的处理:

  • age is null 和age is not null(不能用age =null或age <>null)。
  • SELECT 11+null,返回null(任何值与null计算后得到null)
  • isNull(age,0)–age列用值0替换所有 NULL 条目。
  • NULL的比较问题
  • Null值并不是一个值,任何与Null比较结果一定为Null。
  • 查询空值或者非空值的时候,用的是is null/is not null
  • 按照ANSI SQL标准,select * from T where Data=null 或 Data<>null这两种方式都不返回任何行,只有Data is null才能有返回值。实际工作中遇到如:SELECT * FROM A WHERE id NOT IN ( 2, NULL )等同于.... WHERE a.id <> 2 AND a.ID <> NULL而NULL值不能参与比较运算符,即not in子查询中有null值的时候,则不会返回数据。解决办法是子查询中排除NULL值。
  • order by English,Math desc——先按英语从大到小在按数学成绩从大到小排,当English分一样后才按数学成绩排序。
    order by (English+Math)*1.0/2 desc——按两门平均分排
  • 表中数据是集合,集合是无序的。把order by后有序的集合叫“游标”,有序后就不是集合了。
  • 一条select语句执行顺序(即先查询出符合条件的然后对其排序):找到要查的表,返回出符合条件的数据汇总成结果集1,在1中仅显示指定列汇总成结果集2,对2去重汇总成结果集3,对3进行排序汇总成结果集4,返回4中的Top 12汇总成最终结果集
 1-from,2-on,3-join,4-where,5-group by,6-with cube或with rollup,7-having,8-select,9-distinct,10-order by,11-top
- where name like '安__'--返回所有安开头的3个字的姓名where name like '张[0-9]妹'----返回所有张和妹中间是数字('张[a-z]妹'、'张[0-9a-z]妹'(中间可是数字或字母)、'张[^0-9]妹'(中间不能是数字就行))where name like '%[%]%'——返回所有带‘%’的名字,默认放到[]中实现转义。自定义转义 select * from tbl where name like '%/[/]%' ESCAPE '/'
  • 类型转换函数:cast/convert,前者先出现,后者功能强大。
 SELECT 1+'11'--自动类型转换SELECT 'a'+1--转换失败SELECT 1.1+'11'--转换失败SELECT CAST('11' AS int) +1.1SELECT CONVERT(INT,'11')+1.1SELECT CONVERT(VARCHAR(10),GETDATE(),120)--日期输出格式:"yyyy-MM-dd"SELECT CONVERT(VARCHAR(20),GETDATE(),120)--日期输出格式:"yyyy-MM-dd +时分秒"
  • union,联合结果集,把行联合起来。join,把列连接起来。union会去重和排序、union all不去重也不排序,两者比起来union慢些。
  • 一次往表中插入多条:
 方法1:用union、union all。方法2:select * into tbl from student (tbl表会自动被创建,只是copy数据、列名及数据类型,对于约束不会复制)。select * into tbl from student where 1<>1 ,只复制表结构,效率低。建议:select top 0 * into tbl from student方法3:insert into tbl select * from student (tbl表必须提前建好)
  • 字符串函数
  SELECT LEN('1啊')--字符串个数:2个SELECT DATALENGTH('1啊')--字符串磁盘中大小:3b(字节)SELECT DATALENGTH(N'1啊')--字符串磁盘中大小:4bSELECT LOWER('HI')--hi 转小写SELECT UPPER('hi')--HI 转大写SELECT LTRIM(RTRIM('== ')+LTRIM(' =='))--去掉字符串首尾空格SELECT LEFT('abcd',2) --从左边开始截取几个字符 结果:abSELECT RIGHT('abcd',2) --从右边开始截取几个字符 结果:cdSELECT SUBSTRING('abcd',2,3)--截取串,从坐标轴是2()的字符开始取3个  结果:bcd。给串画一条x轴则a对应1,轴上可以为负或0。如: SELECT SUBSTRING('abcd',-1,3)--结果是‘a’
  • 日期函数 (记忆:add+、diff-、part)
 SELECT SYSDATETIME()-- 高精度时间SELECT DATEADD(second,20,GETDATE())--当前时间增加20 second/minute/hour/day/week/month/yearSELECT * FROM tbl WHERE DATEADD(YEAR,1,joinDate)<=GETDATE()--入职1年以上的人员SELECT DATEDIFF(MONTH,'1987-11-14',GETDATE())--两个日期差,可知道某个人在地球上生存了多久,时间维度可为“second/minute/hour/day/week/month/year”SELECT 工龄=DATEDIFF(DAY,JoinTime,GETDATE())/365,COUNT(1) FROM tbl GROUP BY DATEDIFF(DAY,JoinTime,GETDATE())/365--各工龄的人数SELECT DATEPART(year,GETDATE())--取得当前日期的年部分(结果是int型) 可为“second/minute/hour/day/week/month/year” SELECT YEAR(GETDATE()) 年,month(GETDATE()) 月,day(GETDATE()) 日 --简写只有“年、月、日”SELECT DATENAME(YEAR,GETDATE())--取得当前日期的年部分(结果是varchar型)
  • 内连接
 sql1:SELECT * FROM tbl1 ,tbl2 --结果集是返回笛卡尔积sql2:SELECT * FROM tbl1 a inner join tbl2 b on a.id=b.tId--先得到sql1的笛卡尔积,然后筛选出符合on条件的结果并返回
  • 可空值类型,必须是值类型,所以string不能用。可以:int、double、float、bool。
 int? age=txtAge.Text.Length()==0 ? null : (int?)txtAge.Text;//要给后者转为int?,因为问号表达式要求三者数据类型要一致。string sql="insert into tbl values(@name,@age)";SqlParameter[] pms=new SqlParameter[]{new SqlParameter("@name",SqlDbType.NVarChar,50){Value="张三"}, //SqlDbType.NVarChar,50——必须与数据库中一致 不推荐“new SqlParameter("@name","李四"),”写法new SqlParameter("@age",SqlDbType.Int){ Value=age==null ? DBNull.Value : (object)age} //往DB中insert值null,必须是DBNull.Value};int? n=null; 等价于Nullable<int> n=null;书上说值类型不能为null,int?可以原因是:它是一个结构在里面封装属性HasValue,无值在其为false,当写“if(n==null){}”等价于“if(!n.HasValue){}”,这些工作都编译器帮我们做的。
  • SQL条件控制case-when两种写法
--Case搜索函数,相当于C#的if-else(条件可以是一个范围,推荐实际使用)
select 论坛头衔= case when level>=1 and level<=2 then '菜鸟' when  level>=3 and level<=4 then '老鸟' else '??' end from user
--Case函数,相当于C#中的switch(判断条件只能是一个值,不推荐)
select case level when  1 then '菜鸟' when  3 then '老鸟'  else '??' end as [论坛头衔] from user
  • 扩展:电子教室软件“红蜘蛛多媒体教室 或 TopDomain极限域电子教室 ”

索引

  • SQL server的数据是按页(4KB)存放。索引,是SQL server编排数据的内部方法。
    索引页:数据库中存储索引的数据页;索引页类似字典中按拼音或笔画排序的目录页。
  • 目的就是为了select的快,实际就是对数据排序,当我们创建主键,系统会自动创建为其建主键索引(一个表只能一个,它属于聚集索引)。
  • 索引分为唯一索引,不允许两行具有相同的索引值,一个表可以有多。“聚集索引也叫聚簇索引”(目录顺序与内容顺序一样。像新华字典的拼音方式查字,一个表只能一个)和“非聚集索引”(目录顺序与内容顺序不一样。如字典的偏旁部首找字,一个表可有多个,但是要<249个)。非聚集索引,反应了从多少个角度查询数据,如图书馆,我可按书名找或按价格找等等。主键索引就是一个唯一索引,就是一个聚集索引。
    索引缺点:表建索引后要额外占用存储空间。降低了增、删、改的效率(每次这些操作DB都要维护更新索引)。

    • 通常建索引原则:该列用于频繁搜索;该列用于对数据进行排序(在经常检索即where后、order by后用到的字段上创建索引)。不要创建索引情况:列中仅含几个不同值;表只有几行(小表建索引不划算)
    • (*)即使建了索引,也可能全表扫描,如like、函数、类型转换等。“like ‘aa%’”会用到索引,而“like ‘%aa%’”则肯定不会用索引。
    • 删除索引: drop index T9IX_T8_tage
    • 监控一条sql执行方法:
      打开Sql server的统计信息: 查询 > 查询选项 > 高级 > set statics time、set statics io 选中“包括实际的执行计划”或“估计的执行计划”菜单工具。
      ( 逻辑读取:从缓存中读取数据
      物理读取:从磁盘中读取数据
      预读取:在执行查询时先预测执行“查询计划”需要的数据和索引页,然后在查询实际使用这些页前将它们读入到缓存区。
      读取次数和毫秒数越少越好
      Lob类型包括:text varchar(max) varbinary image等大对象数据。)
    • 当我们不知道为表哪列建索引时,可以用“数据库引擎优化顾问”,流程:工作负荷选择要优化的SQL脚本文件,选择该sql执行的数据库,选择要优化的数据库和表里找到目标数据的目标表,点击“开始分析”,然后找到索引的“定义”列里面脚本执行即可。

子查询

  • 把一个查询结果在另一个查询中使用就是子查询。多会用“in、not in、exists、not exists”。如:select * from ( select col1,col2 from #tmp) as tbl ; select * from tbl where empNo in(select empNo from pr_people where id<10); select * from tbl a where exists (select * from pr_people b where a.empNo=b.empNo and b.id<100)我们写的所有查询都能改为“相关子查询”实现!!!解析本处的含exists语句,该SQL会扫表当扫到第一条时,exists里的sql是true第一条就会返回。
  • 子查询分为:独立子查询(子查询可独立运行);相关子查询(子查询中引用了父查询中的结果)。
  • 分页的sql必须确定按谁排序。
 --TOP版分页DECLARE @page int=2 --第二页内容declare @pSize int=10--每页10条SELECT top (@pSize) * from People where id not in(select top (@pSize*(@page-1)) id from People order by id asc) order by id asc--不用not in版:  select top 7 * from (select top (2*7) * from tbl order by id asc ) as t order by id desc--ROW_NUMBER()版DECLARE @page INT= 2; --页号DECLARE @pSize INT= 10;--每页条数SELECT  *FROM    ( SELECT    row_No = ROW_NUMBER() OVER ( ORDER BY ID ASC )--row_number--生成编号列,over--请按照id列asc排序后为其编号,Emp_NOFROM      B_Employee) tblWHERE   row_No BETWEEN ( @page - 1 ) * @pSize + 1 AND ( @page * @pSize );
  • set、select为变量赋值的区别:
  DECLARE @a intset @a=(SELECT count(*) from tbl)SELECT @a=count(*) from tblprint @a--上述效果一样。set @a=(SELECT empNo from tbl)--当返回多个值,set赋值会报错SELECT @a=empNo from tbl --当返回多个值,select赋值会把最后一个给@aprint @a
  • 左外连和右外连接
    inner join–返回两个表匹配的数据,过滤掉不匹配的数据
    left join-- 返回‘左’表所有数据;‘右’表有匹配的则显示,不匹配的则显示null
    right join–返回‘右’表所有数据;‘左’表有匹配的则显示,不匹配的则显示null

    • left和right互相可以实现同样效果,只是语法不一样。一般用left-join
    • 【连接查询执行顺序】:1.生成笛卡尔积 2.根据on后面条件筛选出匹配的数据 3.添加外部行,到此执行完毕(“添加外部行”我的理解:因为是外连接大原则是要返回左表所有行,然后右表仅显示匹配项)。故,注意:当连接查询,如果是写在where的条件就不要在on后面加and方式。如:“tbl t left join tbl2 b on t.id=b.TId and t.sex=‘男’ ”(先根据on返回目标结果,但是最后又会返回所有主表数据,就会覆盖所以与后面条件不一样)与 “on t.id=b.TId where t.sex=‘男’” 不能等同。
 left join中关于where和on条件的几个知识点:(筛选条件写在where还是on后面解读)1.多表left join是会生成一张临时表,并返回给用户2.where条件是针对最后生成的这张临时表进行过滤,过滤掉不符合where条件的记录,是真正的不符合就过滤掉。3.on条件是对left join的右表进行条件过滤,但依然返回左表的所有行,右表中没有的补为NULL4.on条件中如果有对左表的限制条件,无论条件真假,依然返回左表的所有行,但是会影响右表的匹配值。也就是说on中左表的限制条件只影响右表的匹配内容,不影响返回行数。
结论:1.where条件中对左表限制,不能放到on后面2.where条件中对右表限制,放到on后面,会有数据行数差异,比原来行数要多
  • study、study_req表都有 deleted_Mark(1删除,0未删除)下面三条查询语句分析
--正确,但是麻烦
select * from  study st left join (SELECT * FROM  study_req where deleted_Mark=0) sr on st.study_id = sr.study_id  where st.deleted_Mark=0
--正确???
select * from  study st left join  study_req sr on st.study_id = sr.study_id on sr.deleted_Mark=0 where st.deleted_Mark=0
--错误写法
select * from  study st left join  study_req sr on st.study_id = sr.study_id  where st.deleted_Mark=0 and sr.deleted_Mark=0
  • 自连接:表本身连接本身
--返回笛卡尔积:SELECT * FROM B_Organize a, B_Organize bSELECT a.OrgName,b.OrgName FROM B_Organize a inner join B_Organize b on a.Org_NO=b.FatherID--返回“襄阳市,湖北省;武汉市,湖北省;宜昌市,湖北省;CREATE TABLE [dbo].[B_Organize]([Org_ID] [int] NOT NULL IDENTITY(1, 1),--表id[Org_NO] [int] NOT NULL,--机构号[OrgName] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NOT NULL,--组织机构名称[Visable] [tinyint] NOT NULL,--是否显示在通讯录中[Flag] [tinyint] NOT NULL,--是否为组织机构,1为组织机构,0为用户组[OrderID] [int] NULL,--排序顺序[FatherID] [int] NULL,--上一级节点ID[FatherPath] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL,--组织机构全路径[EffectDate] [datetime] NULL,--启用时间[ExpiredDate] [datetime] NULL,--失效时间[istop] [int] NULL,[orderid_sap] [nvarchar] (50) COLLATE Chinese_PRC_CI_AS NULL)
  • 视图:实际开发过程中要经常查询一些数据,但是要用复杂的sql语句才能查到,我们可将语句封装成视图,下次只需要直接“select * from view_tbls(视图)”就可以了。视图中不存放原始数据。sql server的索引视图存放数据。

    • 视图是无参且只是select语句的集合
    • 创建视图语法:create view view_tbls as select * from tbl–没有where条件select语句(也不能只跟order by,但是它可以与top配合使用是可以的)
    • 好处:降低了数据库复杂度;防止未经许可用户访问敏感数据(一个系统A用户登陆后仅能执行某几个视图来查看对其开放的字段);将多个物理数据库抽象为一个逻辑数据库。

T-SQL编程

  • 声明变量:两个“@@”开头一般是系统变量,不过自己变量时也可加两个“@@”
 declare @name varchar(50)declare @age int或 declare @name varchar(50),@age intPRINT @@VERSION--数据库版本,@@error,最后一次sql错误的错误号(正常返回0,错误则“<>0”),@@identity 最后一次插入的标示值PRINT @@MAX_CONNECTIONS--数据库可同时连接的最大数PRINT @@rowcount--上条sql影响的行数PRINT @@SERVERNAME--服务器名称
  • 使用while循环

    declare @i int=1;
    while (i<10)--括号可不写
    beginprint 'hi'set @i=@i+1break;--跳出循环continue;--继续下次循环
    end
    
  • if语句

    if @i>10
    beginprint 'n大于10'
    end
    else if @i>5
    beginprint 'n大于5'
    end
    else beginprint 'hi'
    end
    
  • 事务:事务一旦开启就两种可能"ROLLBACK,COMMIT"。 事务分类自动提交事务(当我们执行一条insert、update、delete,如果出错就回滚);隐式事务(每次执行一条sql,数据库自动帮我们打开一个事务,但是需要手动提交或回滚事务);显示事务(需要手动打开事务,手动提交或回滚事务)

    • [显示事务]–(常用)
    BEGIN TRANSACTION --开始转账事务 或 “begin tran”
    DECLARE @flag INT=0 --汇总的@@error值
    UPDATE tbl SET money =money+100 WHERE id='u001'--给账号1加100元
    SET @flag=@flag+@@ERROR --必须在每条sql后面进行累加操作
    UPDATE tbl SET money =money-100 WHERE id='u002' --给账号2减100元,假设该人只有108元,而该表有对money检查约束(该字段最少10),故必会发生异常
    SET @flag=@flag+@@ERROR
    IF(@flag>0) --有一条sql语句出错,就回滚事务
    BEGIN ROLLBACK--回滚
    END
    ELSE BEGIN COMMIT--没出错就提交事务
    END
    
    • [隐式事务]–(少用)开启后,每个SQL语句都自动按事务模式执行
    SET IMPLICIT_TRANSACTIONS ON--打开隐式事务
    INSERT INTO tbl VALUES('12','123123')--当没写COMMIT,则此表一直被占用,此时执行select时给人感觉是耗费很久但是还是查询不到结果。
    COMMIT
    SET IMPLICIT_TRANSACTIONS off--关闭隐式事务
    
  • 事务的ACID特性:原子性(各步操作不可分隔,要么都执行要么都不执行)、一致性(事务完成后所有数据一致,银行总钱数在“已有数+n次转入-n次转出”后不会发生混乱)、隔离性(并发事务在执行时,是互相独立的别人不可干预)、持久性(数据会被永久保存)

  • Trigger(触发器,枪的扳机)一个特殊的存储过程,事件触发后自动调用它。具备事务功能;它能在多表之间执行特殊业务规则。触发器是在对表进行插入、删除、改时自动执行的存储过程(它是与表相关的,是自动执行,不能直接调用)。触发器是一种高级约束,可以定义比check约束更复杂的约束。扩展:SQLSERVER的触发器

    • DML触发器:Inserte、delete、update ;DDL触发器:create table/create database/alter/drop等
    • [“增、删、改”触发器原理]——触发器激发时,系统会在内存准备deleted和inserted两个表(只读,触发器执行完毕后自动删除,表结构与关联表完全一致),只有在触发器体内才能访问,其地方访问不到。要insert记录到tbl表,先插入到tbl表,然后在往inserted表插入一条。插入成功,则inserted表会释放,插入失败,回滚会清空两表记录。要删除id=3:先把tbl表的id=3数据移到deleted表。删除失败,回滚是把deleted表恢复到tbl表。 要udpate id=3:先把id=3的数据移到deleted表,然后插入新的记录到inserted表和tbl表
    • After触发器:执行后的触发器。建立在普通表上,视图临时表不起作用。Instead of触发器:执行前的触发器,可建在表和视图上。每个表只能创建一个 INSTEAD OF 触发器,但可以有多个 AFTER 触发器。
    --为tbl表创建执行删除后把被删除的内容备份到备份表
    CREATE TRIGGER triName_delete ON tbl
    AFTER delete
    AS
    BEGININSERT INTO tbl的备份表 VALUES('','') SELECT * FROM deleted
    END
    
    • 触发器使用建议:尽量避免在触发器中执行耗时的复杂的操作,因为触发器会与sql语句认为在同一个事务中,事务不结束,就无法释放锁。触发器编写时要多注意对多行触发时的处理。
  • 存储过程

    • 以sp和xp开头的都是系统存储过程,在master数据库中
 sp_databases--返回所有数据库sp_helpdb——列出所有数据库sp_renamedb——更改数据库名称(sp_password--添加修改登录账户的密码)sp_tables--返回某个库所有表(SELECT * FROM INFORMATION_SCHEMA.TABLES)sp_columns 'pr_people'--返回某个表所有字段信息 (SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='pr_people')select * from sysobjects where xtype='V'--库中所有的视图sp_helptext——查看存储过程、触发器、视图的实体文本sp_help 'pr_people'——看某个表所有信息sp_helpconstraint 'pr_people'——看某个表约束sp_helpindex  'pr_people'——看某个表索引sp_stored_procedures--列出所有存储过程(含函数)
  • 存储过程缺点:大量业务逻辑写到存储过程中,访问压力转到数据库服务器了,优化数据库比优化代码难。
    优点:同样的sql代码块,proc速度要快(保存到数据库后就是编译过的);允许模块程序设计(类似方法复用);提高系统安全性(防止SQL注入);减少网络流量(只需要传存储过程名)
  • 存储过程与函数区别:二者本质上没区别,只是函数只能返回一个变量(这个变量可是一个值或表对象,常用系统函数有getDate()、count()、sum()等),而存储过程可返回多个。select后面可跟一个函数,而存储过程不行。函数不能用临时表,只能是表变量。
  • 存储过程例子
--无参存储过程create proc usp_myProcas beginprint 'hi'end-- 自己写带2个参数存储过程 exec usp_myProc 1,2 或exec usp_myProc @n1=1,@n2=2 create proc usp_myProc @n1 int=0,@n2 int--可以给默认值as beginselect @n1+@n2end-- 输出参数的存储过程 适用情况:当不仅需要返回查询结果还需要返回其他值,如分页存储过程返回结果和总条数。create proc usp_myProc @n1 int=0,@rowcount int output --输出参数关键字as beginselect * from tbl where id=@n1set @rowcount=(select count(*) from tbl where id=@n1)end--调用语句:declare @rc int; exec usp_myProc 12,@rc output; print @rc;(下例子out与C#的out类似)
○ 有这样一个需求:创建查询机构表存储过程,传入参数机构号多个用逗号分隔如"19999999,10000104"
实现思路:
--方法1:自定义的split函数
create function [dbo].[f_split](@c varchar(2000),@split varchar(2))
returns @t table(col varchar(20))
as
beginwhile(charindex(@split,@c)<>0)begin insert @t(col) values (substring(@c,1,charindex(@split,@c)-1))set @c = stuff(@c,1,charindex(@split,@c),'')endinsert @t(col) values (@c)return
end
--调用:SELECT * FROM Organize  WHERE Org_NO IN( select * from f_split('1,2,3',',') )以table形式返回分隔后值
--方法2:
DECLARE @s VARCHAR(5000);DECLARE @orgNo VARCHAR(5000)='19999999,10000104'
SET @s='SELECT * FROM Organize WHERE Org_NO IN('+@orgNo+')'
EXEC (@s)
  • 扩展:SQL中存储过程out与output有什么不同、存储过程中的out,output,return 的使用
CREATE PROCEDURE Proc_Test @INPUT int,@OUTPUT int output
AS BEGINSET NOCOUNT ON;--不返回受影响行数SELECT @OUTPUT=@INPUTRETURN @INPUT+1--注意return
END
--调用:
DECLARE @OUT int,@Rt int
EXEC @Rt=Proc_Test3 10,@OUT output
SELECT @Rt,@OUT

数据库优化

  • 数据库锁、数据库优化 (scale up–纵向扩展 向已有机器内加内存 scale out–横向扩展 加机器)

    • “修改、删除、添加”时会加“写锁(也叫x锁/排他锁,表有它则表示此表被独占,其他锁就不能加了就连查都不让查)”;“查询”加“读锁(也叫s锁/共享锁,多个查询sql可在一个表上加多个读锁,有了读锁后就不能加写锁)”。SqlServer中select语句会引起的死锁。通过“SELECT * FROM People WITH(NOLOCK)”可查询加写锁的表,但是可能会查询到脏数据。
    • 总结:
  • 脏读含义:用户A对一个资源做了修改,此时用户B正好拿到了A修改的结果,但是B拿走后A又进行了回滚,B拿到与真实的不同。通过加锁机制可以避免脏读(因为锁可以做到:用户甲查询时,则不让用户乙改变表内容(因为甲查询给表加读锁了,就不让加写锁)或用户乙改变表内容时,不让用户甲查(因为给表加写锁了,就不让加读锁)。一个表可以被多个用户同时查)。
  • with(nolock)作用是对查询的表不加读锁。这样好处是,它既不会被排他锁阻塞也不会去阻塞排他锁。但是会引起脏读。它允许SELECT语句读取正在修改中的数据。可提高并发时的性能,效果要在并发环境才可看到,多用在对读出的数据精度要求不高的情况下。
  • 锁:
  • 一个表的读锁可以有多个。
  • 一个表的写锁只能有一个。
  • 一个表的读锁与写锁互斥。
  • 有两个使用频率很高的表。A人独占表1中又准备独占表2;B人独占表2中又准备查表1。数据库自己有一个线程会查是否有死锁,有的话强行牺牲一个竞争者来解决死锁问题。具体的SqlServer表死锁的解决方法:先找到发生死锁的表select request_session_id spid,OBJECT_NAME(resource_associated_entity_id) tableName,* from sys.dm_tran_locks where resource_type='OBJECT'(在查询时间点数据库加锁情况的快照,列出来的不都是死锁但是死锁包含其中),然后对表解锁KILL 52(杀掉被锁的进程ID)。(sp_lock,SQL Server 2000就有,查看当前阻塞的数据表,以便分析程序,解决问题。)
  • SQL Server可设置锁超时,超时可以释放死锁。怎么设置与查看锁的超时时间?
  • select @@LOCK_TIMEOUT——返回会话的锁超时时间,单位为毫秒。默认-1,代表没有超时时间。而0,在发生资源锁定时,不做任何等待,直接返回1222错误。
  • SET LOCK_TIMEOUT 1800——超时期限设置为1,800毫秒。仅对当前会话有效,对新会话无效。
  • 弊端:超时值设置不恰当,则SQL server会不分好坏超时就返回错误。
  • 具体怎么找到死锁?SQL server管理器,工具 → SQL SERVER Profiler → 跟踪属性 → “常规”选项卡,“使用模板”里选TSQL_Locks → “事件选择” 勾选“Locks”的“Deadlock graph”等有Deadlock字样的选项 → 点确定统计结果中“EventClass”是“Deadlock graph”是以图形显示死锁的图形事件。资料1、资料2
  • 死锁会造成系统反应超慢(类似连接超时),避免死锁办法:
    1、sql操作表顺序尽量一致(A人操作要占表1,2;B操作也要占表1,2,这样在写sql语句时都先执行1,再执行2)。
    2、查询sql添加with(nolock)就是不加s锁(如:SELECT * FROM tbl with(nolock) WHERE id=1)。
    3、一个查询join非常多的表易引起死锁,解决办法是使用临时表(其暂存在tempdb,每次会话结束就会释放):让一个原始表跟临时表进行join查询 → 临时表 → 原始表2进行join查询 → 临时表 → 原始表3进行join查询。同一时间只对一个表加s锁。
    4、分库:水平分库,垂直分库。
    5、数据库集群,读写分离
  • 下面一些场景可以使用WITH(NOLOCK)
    1: 数据很少变更的表:基础数据表、历史数据表。
    3:业务允许出现脏读涉及的表。
    4:数据量超大的表,出于性能考虑,而允许脏读。

[扩展]

  • 深入浅出SQL Server中的死锁, 在多并发的环境中,死锁不可避免,只能尽量的优化查询/索引/隔离等级来降低死锁发生的可能性。
  • T-SQL查询进阶—理解SQL Server中的锁
  • 人为模拟一个死锁——使用sys.dm_tran_locks处理死锁问题。
  • DMV(Dynamic Management Views,动态管理视图)是SQL Server内核的元数据,通过对这些元数据分析,从而进行性能分析。
  • 当查询在SQL Server中运行时,SQL Server会自动的将此次活动的相关信息记录下来,并且保存在内存之中,这些活动信息,就称之为:DMV。
  • DMV只会在2005及以上的版本存在,2000没有引用DMV的概念。
  • SQL中利用DMV进行数据库性能分析
  • sql优化之(DMV)
  • SQL Profiler工具简介 ,Profiler可以用自定义一个跟踪模板,更多见“跟踪模板”部分。
  • 一般企业DB优化历程:加硬件 → 分库(水平分库→垂直分库) → 数据库集群 → 用缓存
  • 水平分库:(1个系统有1台web服务器1台DB服务器,通过为活跃数据表增加对应history表方式缓解常用表压力;或主副库放多台服务器来分摊压力)
    1、数据库文件放到不同服务器硬盘上,充分利用磁盘的IO性能。
    2、表分区,一个大表,分拆到不同文件里。按某个条件(如日期)分区。分拆的数据文件放到不同服务器硬盘里。
    3、主动分区:当前表,放近“3天”(时间根据实际情况确定)数据,表只有主键索引,不加其他索引,写频繁时忌讳加过多的索引(因为写时会更新全表索引),历史数据放历史表。
  • 垂直分库:(我的理解:1个系统有1台web服务器1台DB服务器,通过加机器把库拆分成n个库,然后放到n台DB服务器上,来分摊压力。如:csdn的博文数据库、收藏夹数据库)
    1、把一个数据库根据业务模块分成多个数据库。用户相关的数据放到用户数据库。订单相关数据放到订单数据库上。如果同样的用户信息重复存在于不同业务系统数据库里,则弊端是数据同步很麻烦且会发生滞后问题!!!——我2014年到2018年期间维护的多个系统都有自己的用户信息表,他们这些用户信息同步方式是先从SAP同步数据到OA然后同步其他子系统。

  • 数据库运维人员工作时间:凌晨2、3点。数据库可在“管理> 维护计划”每隔一段时间执行分表。

  • [数据库集群]:读写分离。但是有数据同步问题。“一个主库,多个从库” → “多主库,多从库”。互联网应用的最好用:MySQL、oracle,最好不用SQL server。

  • [缓存解决,磁盘IO瓶颈] 微博先放到Redis(解决读写瓶颈),然后再用MySQL保证数据完整性。

  • 大表数据连接查询优化 临时表
    数据库中有两个大表:userInfo(100w)、orderInfo(1000w)表,需要把所有用户数据和所有订单数据关联成一起后显示,如果直接连接查询,则要从笛卡尔集条数是“100w*1000w”条筛选,查询速度会很慢。
    优化思路:分别对两个单表进行查询出的结果放到内存,在内存里组装数据。两个大表不能直接连接,表上锁时间不能过长。
    1、把连接查询进行分解,转成单个大表的查询最后在内存组装数据。
    2、使用临时表(select * into #tbl from userInfo),解决“查询频繁造成死锁问题” tbl1 inner join tbl2 on a.id=b.tid–查询会锁tbl1和tbl2,尽量减少在原始表上加锁。用临时表来降低原始表被锁的情况。

    • 表变量:一个变量但是是个表。
    • 临时表:可以创建“本地和全局”临时表。本地临时表仅在当前会话中可见(sql 2008关闭“创建新查询”建的tab就是关闭会话);全局临时表在所有会话中都可见。##tbl,两个‘#’是全局临时表,一个‘#’是本地临时表。存储在tempdb数据库,在sysobjects 表可查询临时表信息。除非使用DROP TABLE 语句显式除去临时表,否则临时表将在退出其作用域时由系统自动除去。当创建全局临时表的会话结束时,最后一条引用此表的T-SQL语句完成后,将自动除去。
  • sql优化自己总结:一个表查询执行时间不能过长也不能过频繁,要连接的表尽量少,采用临时表连接。频繁写入的表尽量小,索引尽量少(最好只有PK索引)。注意s/x锁的问题。select语句where后面常用的字段巧用索引和WITH(NOLOCK)。
    [扩展] 表变量、临时表

  • 表变量在T-SQL语句执行结束后立刻自动被清除(选中下面SQL块,执行没问题,然后在单独选中SELECT * FROM @tb1执行就会异常)。

DECLARE @tb1 Table
(Id int,Name varchar(20),Age int
)
INSERT INTO @tb1 VALUES(1,'刘备',22)
SELECT * FROM @tb1/*临时表与join的使用*/
SELECT  soh.CustomerID ,MIN(soh.OrderDate) AS OrderDate
INTO    #MinOrderDates
FROM    Sales.SalesOrderHeader soh
GROUP BY soh.CustomerID;
SELECT  soh.CustomerID ,soh.SalesOrderID ,soh.OrderDate
FROM    Sales.SalesOrderHeader sohJOIN #MinOrderDates t ON soh.CustomerID = t.CustomerIDAND soh.OrderDate = t.OrderDate
GROUP BY soh.CustomerID;
DROP TABLE #MinOrderDates;
  • 数据库开发步骤:根据需求分析文档 -> Excel粗略列出要用到表 -> 在数据库设计器中建表 -> 绘制各表的主外键关系 -> 在设计器中得到sql脚本 -> 在SQL Server 2008中执行sql脚本即完成数据库创建。在开发过着,DB设计器是一个设计DB直观、省力(帮你生成sql)、excel表格变成sql脚本的高效工具。这里推荐一个简单有效的设计器:EZDML(fee) 。扩展:如何设计合理高效的数据库

技术笔记:.Net全套就业班视频教程——数据库相关推荐

  1. WEB前端之HTML5/4高薪就业班视频教程【课件】-丁鹏-专题视频课程

    WEB前端之HTML5/4高薪就业班视频教程[课件]-162人已学习 课程介绍         本课程包含HTML4.HTML5相关知识点,讲解细致. QQ答疑群: 807662232(我们因技术而结 ...

  2. 传智播客上海java培训就业班 视频教程

    传智播客上海java培训就业班 视频教程 传智播客上海java培训就业班 视频教程 传智播客上海java培训就业班 视频教程 下载地址:百度网盘

  3. 传智播客JavaEE 第168期就业班视频教程 Java自学课程

    领取方式:关注微信公众号:Java脱口秀     回复"黑马"免费领取传智播客JavaEE 第168期就业班视频教程 Java自学课程.回复"资料" 领取更多J ...

  4. 【备注】某某培训机构32期JavaEE系列视频教程就业班视频教程

    课程目录: 01-项目概述(背景介绍)_ 02-项目概述(常见的软件类型)_ 03-项目概述(软件开发的流程)_ 04-项目概述(技术选型)_ 05-搭建数据库环境_ 06-搭建maven项目环境(配 ...

  5. python就业班讲义_64G 最新 Python 就业班 视频教程 全集 含 pdf 源码 资料

    目录太多只放一部分了 │ ├─01基础 │  │  补充资料.zip │  │ │  ├─第1节 linux操作系统基础 │  │  ├─01.Linux以及命令 │  │  │  │  01-课程介 ...

  6. 2015年传智播客JavaEE 第168期就业班视频教程day38-SSH综合案例-1

    为什么需要划分模块呢?因为需要知道一些大致的功能,其次呢需要知道我们后台需不需要对它进行维护.如果需要呢那它肯定是一个单独的模块, 1.1    网上商城需求分析: 1.1.1 前台:用户模块 注册: ...

  7. 2020年黑马python视频教程5.0新版课程_黑马Python就业班5.0-最新2020人工智能

    2020年最新版Python5.0,全新升级!人工智能数据分析,爬虫,机器学习,WEB全栈开发 Python开发特训班课程,以实战项目出发, 将部署运维和测试开发内容整合的项目中, 真正让学员参与到实 ...

  8. 精品奉献传智播客(C#.Net)就业班全套视频课程 Czbk .Net视频教程 完整版

    精品奉献.Net基础视频教程 亲情奉献全套精品.Net基础视频教程之02-C#基础 亲情奉献全套精品.Net基础视频教程之04-流程控制 亲情奉献全套精品.Net基础视频教程之06-函数 亲情奉献全套 ...

  9. unity3D-游戏/AR/VR在线就业班 C#入门访问修饰符学习笔记

    unity3D-游戏/AR/VR在线就业班 C#入门访问修饰符学习笔记 点击观看视频学习:http://edu.csdn.NET/lecturer/107 访问修饰符 public --公共的,在哪里 ...

  10. 七天学会Photoshop视频教程-CSDN就业班-专题视频课程

    七天学会Photoshop视频教程-50人已学习 课程介绍         通过学习本课程,学员熟练掌握Photoshop(PS)软件的各种操作: 包括:软件安装配置,图层操作,工具栏所有工具使用方法 ...

最新文章

  1. python程序实例源代码-Python 神经网络手写识别实例源码
  2. JavaScript实现knuth-morris-pratt(KMP)算法(附完整源码)
  3. 王道408数据结构——第八章 排序
  4. 软件配置管理(五)常用重构技巧
  5. 华为云联合浙江大学构建新冠科研开放知识图谱
  6. python3第三方模块安装路径_查看python及其第三方库的版本和安装位置
  7. (8)VTK 鼠标左右键控制模型旋转
  8. Linux 系统-----vim命令详解
  9. EP100的局部地址、逻辑地址和全局地址
  10. robotium android,Robotium 测试Android apk安装包
  11. Android shell 授权文件执行权限
  12. php支付宝接口参数错误,php支付接口_php支付宝支付接口程序及参数详解
  13. 关于微信表情及输入法emoji显示问题解决方案
  14. 小冲哥c语言视频自学网,C语言二级教学视屏课件_51自学网_小冲哥.doc
  15. 石墨笔记,熊掌记和Effie哪个更适合up主?
  16. 英语六级(词组、同义替换)
  17. 影子系统、沙盒、虚拟机
  18. 一梦江湖获取服务器信息后没有登录,一梦江湖登录不上怎么办 登录不上解决方案...
  19. TiKV 集群版本的安全迁移
  20. AnnotationMethodHandlerAdapter废弃的解决方法

热门文章

  1. 前端激荡三十年(一本最详细的编年史册)
  2. 推荐一款鼠标手势的软件,开源且免费
  3. android win8 磁贴效果第三方库,Win8巧用动态磁贴让浏览更轻松
  4. 医院病房监护系统和图书管理系统数据流图
  5. 吾爱破解网站访问出错
  6. Python3判断字符中英文数字符号
  7. 基于微信小程序的药店管理系统毕业设计
  8. SpringBoot + screw 一键生成数据库文档,告别CV大法,解放生产力
  9. c语言求球的体积用const,牛客练习赛41 E.球的体积并(计算几何)
  10. 【PTA】【C语言】球体的表面积及体积