您的位置:首页 > 数据库

数据库知识总结

2016-08-05 15:59 169 查看
表(Table)和视图(View)的区别和联系?

在SQL中,视图是基于SQL语句的结果集的可视化的表。视图包含行和列,就像一个真实的表。视图中的字段就是来自一个或多个数据库中的真实的表中的字段。我们可以向视图添加SQL函数、WHERE以及JOIN语句,我们也可以提交数据,就像这些来自于某个单一的表。

区别:

1. 视图是已经编译好的SQL语句,而表不是;

2. 视图没有实际的物理记录,而表有;

3. 表是内容,视图是窗口;

4. 表只用物理空间而视图不占用物理空间,视图只是逻辑概念的存在,表可以及时对它进行修改,但视图只能有创建的语句来修改;

5. 表是内模式,视图是外模式;

6. 视图是查看数据表的一种方法,可以查询数据表中某些字段构成的数据,只是一些SQL语句的集合。从安全的角度说,视图可以不给用户接触数据表,从而不知道表结构;

7. 表属于
全局模式
中的表,是
实表
;视图属于
局部模式
的表,是
虚表


8. 视图的建立和删除只影响视图本身,不影响对应的基本表;

联系:

1. 视图(view)是在基本表之上建立的表,它的结构(即所定义的列)和内容(即所有数据行)都来自基本表,它依据基本表存在而存在。

2. 一个视图可以对应一个基本表,也可以对应多个基本表。

3. 视图是基本表的抽象和在逻辑意义上建立的新关系

内模式和外模式?

外模式

外模式又称
子模式
,对应于
用户级
。它是某个或某几个用户所看到的数据库的数据视图,是与某一应用有关的数据的逻辑表示。外模式是从模式导出的一个子集,包含模式中允许特定用户使用的那部分数据。用户可以通过外模式描述语言来描述、定义对应于用户的数据记录(外模式),也可以利用数据操纵语言(DML)对这些数据记录进行。
外模式反映了数据库的用户观


内模式

内模式又称
存储模式
,对应于
物理级
,它是数据库中全体数据的内部表示或底层描述,是数据库最低一级的逻辑描述,它描述了数据在存储介质上的存储方式翱物理结构,对应着实际存储在外存储介质上的数据库。内模式由内模式描述语言来描述、定义,
它是数据库的存储观


模式

模式又称
概念模式
逻辑模式
,对应于
概念级
。它是由数据库设计者综合所有用户的数据,按照统一的观点构造的全局逻辑结构,是对数据库中全部数据的逻辑结构和特征的总体描述,是所有用户的公共数据视图(全局视图)。它是由数据库管理系统提供的数据模式描述语言(DDL)来描述、定义的,体现、反映了数据库系统的整体观。

事务的四个特性,以及各自的特点?

事务具有4个基本特性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。简称ACID特性。

原子性
:一个事务中所有的数据库操作,是一个不可分割的整体,这些操作要么全部执行,要么全部无效果。

一致性
:一个事务独立执行的结果,将保持数据库的一致性,即数据不会因事务的执行而被破坏。在事务执行过程中,可以违反一致性原则,并产生一个临时的不一致状态。比如在转账过程中,会出现暂时的数据不一致的情况。当事务结束后,系统又回到一致的状态。不过临时的一致性不会导致问题,因为原子性会使得系统始终保持一致性。

隔离性
:在多个事务并发执行的时候,系统应该保证与这些事务先后单独执行时的结果一样,即并发执行的任务不必关心其他事务。对于每一个事务来讲,那一刻看起来好像只有它在修改数据库一样。事务系统是通过对后台数据库数据使用同步协议来实现隔离性的。同步协议使一个事务与另外一个事务相分离。如果事务对数据进行了锁定,可以使并发的事务无法影响该数据,直到锁定解除为止。

持久性
:一个事务一旦完成全部操作以后,它对数据库的所有操作将永久地反映在数据库中。持久性保证了系统在操作的时候免遭破坏。持久性主要是为了解决机器故障、突然断电、硬盘损坏等问题而出现的。为了达到持久性,系统一般都保留了一份日志。一旦出现故障,就可以通过日志将数据重建。

事务的隔离

假设同一个A和B两个同时并发操作数据库,A和B执行的任务如下:

从数据库中读取整数N,将N随机加上10或者20,将新的N更新回数据库。这两个并发执行的实例可能发生下面的执行顺序。

A从数据库中读取N,当前数据库中N=0;

B从数据库中读取N,当前数据库中N=0;

A将N加10,并更新入数据库,当前数据库中N=10;

B将N加20,并更新入数据库,当前数据库中N=20;

可以看到由于数据库出现了交叉存取的操作,B所读取的N是过期的版本,即A在写回数据之前的版本。这样当B更新的时候,将会覆盖A的操作,这就是著名的“更新丢失”问题。那么应该如何避免这种情况的发生呢?

解决此类问题的方法就是为数据库加锁,以防止多个组件读取数据,通过锁住事务所用的数据,能保证在打开锁之前,只有本事务才能访问数据。这样就避免了交叉存取的问题。这和操作系统中的PV操作原理类似。

由于锁将其他并发的事务排除在数据库更新之外,所以这会导致性能的严重下降。为了提高性能,事务将锁分为两种类型:只读锁和写入锁。只读锁是非独占的,多个并发的事务都能获得只读锁;写入锁是独占的,任意时间只能有一个事务可以获得写入锁。

事务的隔离级别

由于隔离性是通过加锁的方式获得的,而锁会降低系统的性能,所以事务提供了控制隔离程度的机制。如果使用较高的隔离级别,则事务会比较好的与其他事务相隔离,当然也会带来大量的系统开销;如果使用较低的隔离级别,则事务的隔离性会比较差,但是能获得更好的性能。

事务的隔离级别分为四种:READ_UNCOMMITED、READ_COMMITED、REPEATABLE_READ、SERIALIZABLE

要理解这些隔离级别的差异必须首先弄清如下几个概念:脏读、不可重复读、幻影读取

脏读:假设同一个A和B两个同时并发操作数据库,A和B执行的任务如下:从数据库中读取整数N,将N加上 10,将新的N更新回数据库。这两个并发执行的实例可能发生下面的执行顺序。

A从数据库中读取整数N,当前数据库中N=0;

N加上10,并将其更新到数据库中,当前数据库中N=10。然而由于A的事务还没有提交,所以数据库更新还没有称为持久性的;

B从数据库中读取整数N,当前数据库中N=10;

A回滚了事务,所以N恢复到了N=0;

B将N加上10,并将其更新到数据库中,当前数据库中N=20;

这里出现了B在A提交之前读取了A所更新的数据,由于A回滚了事务,所以数据库中出现了错误的数据20。尽管A回滚了事务,但是A更新的数据还是间接的通过B被更新到了数据库中。这种读取了未提交的数据的方法就叫脏(dirty)读问题。

不可重复读:当一个用户从数据库中读取数据的时候,另外一个用户修改了这条数据,所以数据发生了改变,当再次读取的时候就出现了不可重复读取问题。比如:

A从数据库中读取整数N;

B以一个新的值更新N;

当A再次从数据库中读取N的时候,会发现N的值变了;

幻影读取:幻影读取指的是在两次数据库操作读取操作之间,一组新的数据会出现在数据库中。比如:

A从数据库检索到了一些数据;

B通过Insert语句插入了一些新数据;

A再次查询的时候,新的数据就会出现;

了解了这几个概念,下面来看一下四种事务的隔离级别的区别:

使用READ_UNCOMMITED级别,会导致脏读问题、幻影读取问题和不可重复读取问题。在需要敏感计算任务的事务中,这样的模式是不太适合的;

使用READ_COMMITED级别,可以解决脏读问题,但是还会有幻影读取问题和不可重复读取问题。这种级别一般用于制作报表。这种模式是大部分系统的默认级别;

使用REPEATABLE_READ级别,可以解决脏读问题和不可重复读取问题,但是会有幻影读取问题;

使用 SERIALIZABLE级别可以解决脏读问题、幻影读取问题和不可重复读取问题。这是最严格级别的隔离级别;

SQL语句执行顺序? (博客地址)

查询中用到的关键词主要包含六个,并且他们的顺序依次为
SELECT--FROM--WHERE--GROUP BY--HAVING--ORDER BY
。其中select和from是必须的,其他关键词是可选的,这六个关键词的执行顺序与SQL语句的书写顺序并不是一样的,而是按照
FROM--WHERE--GROUP BY--HAVING--SELECT--ORDER BY
的顺序来执行 。

FROM
: FROM字句组装来自不同数据表的数据,执行顺序为从后往前、从右到左。

表名(最后面的那个表名为驱动表,执行顺序为从后往前, 所以数据量较少的表尽量放后);

oracle的解析器按照从右到左的顺序处理,FROM子句中的表名,FROM子句中写在最后的表(基础表 driving table)将被最先处理,即最后的表为驱动表,在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指被其他表所引用的表;

多表连接时,使用表的别名并把别名前缀于每个Column上。可以减少解析的时间并减少那些由Column 歧义引起的语法错误.

WHERE
: WHERE字句基于指定的条件对记录行进行筛选,执行顺序为自下而上、从右到左。

ORACLE 采用自下而上从右到左的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾。

GROUP BY
: group by子句将上面过滤的数据划分为多个分组,执行顺序从左往右分组。

提高GROUP BY 语句的效率, 可以通过将不需要的记录在GROUP BY 之前过滤掉。即在GROUP BY前使用WHERE来过虑,而尽量避免GROUP BY后再HAVING过滤。

使用聚集函数进行计算


HAVING
: 使用having子句筛选分组。

避免使用HAVING 子句, HAVING 只会在检索出所有记录之后才对结果集进行过滤. 这个处理需要排序,总计等操作.

如果能通过WHERE 子句在GROUP BY前限制记录的数目,那就能减少这方面的开销.

(非ORACLE 中)ON、WHERE、HAVING 这三个都可以加条件的子句中,ON 是最先执行,WHERE 次之,HAVING 最后,因为ON 是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据,按理说应该速度是最快的,

WHERE 也应该比HAVING 快点的,因为它过滤数据后才进行SUM,在两个表联接时才用ON 的,所以在一个表的时候,就剩下WHERE 跟HAVING比较了。

在这单表查询统计的情况下,如果要过滤的条件没有涉及到要计算字段,那它们的结果是一样的,只是WHERE 可以使用RUSHMORE 技术,而HAVING 就不能,在速度上后者要慢。

如果要涉及到计算的字段,就表示在没计算之前,这个字段的值是不确定的,WHERE 的作用时间是在计算之前就完成的,而HAVING 就是在计算后才起作用的,所以在这种情况下,两者的结果会不同。

在多表联接查询时,ON 比WHERE 更早起作用。系统首先根据各个表之间的联接条件,把多个表合成一个临时表后,再由WHERE 进行过滤,然后再计算,计算完后再由HAVING 进行过滤。

由此可见,要想过滤条件起到正确的作用,首先要明白这个条件应该在什么时候起作用,然后再决定放在那里。

SELECT
: 查看结果集中的哪个列,或列的计算结果。少用*号,尽量取字段名称。

ORACLE 在解析的过程中, 会将依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 使用列名意味着将减少消耗时间。

ORDER BY
:按照什么样的顺序来查看返回的数据。执行顺序为从左到右排序,很耗资源。

SQL调优的手法?

创建必要的索引:在经常需要进行检索的字段上创建索引。创建索引给检索带来的性能提升往往是巨大的,因此在发现检索速度过慢的时候应该首先想到的就是创建索引。

使用预编译查询:程序中通常是根据用户的输入来动态执行SQL语句,这时应该尽量使用参数化SQL,这样不仅可以避免SQL注入漏洞攻击,最重要数据库会对这些参数化SQL执行预编译,这样
第一次执行的时候DBMS会为这个SQL语句进行查询优化并且执行预编译
,这样以后再执行这个SQL的时候就直接使用预编译的结果,这样可以大大提高执行的速度。

调整WHERE字句中的连接顺序:DBMS一般采用
自下而上
的顺序解析WHERE子句,根据这个原理,表连接最好写在其他WHERE条件之前,那些可以过滤掉最大数量记录。

SELECT语句中避免使用’*’:SELECT *比较简单,但是除非确实需要检索所有的列,否则将会检索出不需要的列,这回增加网络的负载和服务器的资源消耗;即使确实需要检索所有列,也不要使用SELECT *,因为这是一个非常低效的方法,DBMS 在解析的过程中,会将*依次转换成所有的列名,这意味着将耗费更多的时间。

尽量将多条SQL语句压缩到一句SQL中:每次执行SQL的时候都要建立网络连接、进行权限校验、进行SQL语句的查询优化、发送执行结果,这个过程是非常耗时的,因此应该尽量避免过多的执行SQL语句,能够压缩到一句SQL执行的语句就不要用多条来执行。

用WHERE子句替换HAVING子句:避免使用
HAVING
子句,因为
HAVING
只会在检索出所有记录之后才对结果集进行过滤。如果能通过
WHERE
子句限制记录的数目,那就能减少这方面的开销。
HAVING
中的条件一般用于聚合函数的过滤,除此而外,应该将条件写在
WHERE
子句中。

使用表的别名:当在SQL语句中连接多个表时,请使用表的别名并把别名前缀于每个列名上。这样就可以减少解析的时间并减少那些由列名歧义引起的语法错误。

EXISTS
替代
IN
:在查询中,为了满足一个条件,往往需要对另一个表进行联接,在这种情况下,使 用
EXISTS
而不是
IN
通常将提高查询的效率,因为
IN
子句将执行一个子查询内部的排序和合并。

用表连接替换
EXISTS
:通常来说,表连接的方式比
EXISTS
更有效率,因此如果可能的话尽量使用表连接替换
EXISTS


避免在索引列上使用计算:在WHERE子句中,如果索引列是计算或者函数的一部分,DBMS的优化器将不会使用索引而使用全表扫描。同样的,不能在索引列上使用函数,因为函数也是一种计算,会造成全表扫描。

UNION ALL
替换
UNION
:当SQL语句需要
UNION
两个查询结果集合时,即使检索结果中不会有重复的记录,如果使用
UNION
这两个结果集同样会尝试进行合并,然后在输出最终结果前进行排序。因此,如果检索结果中不会有重复的记录的话,应该用
UNION ALL
替代
UNION
,这样效率就会因此得到提高。

避免隐式类型转换造成的全表扫描

防止检索范围过宽:如果DBMS优化器认为检索范围过宽,那么它将放弃索引查找而使用全表扫描。 下面是几种可能造成检索范围过宽的情况:

使用
IS NOT NULL
或者不等于判断,可能造成优化器假设匹配的记录数太多。

使用
LIKE
运算符的时候,”a%”将会使用索引,而”a%c”和”%c”则会使用全表扫描,因此”a%c”和”%c”不能被有效的评估匹配的数量。

如何防止SQL注入?谈谈六个防止SQL注入式攻击的建议

注入原理:SQL注入式攻击的主要形式有两种。一是直接将代码插入到与SQL命令串联在一起并使得其以执行的用户输入变量。上面笔者举的例子就是采用了这种方法。由于其直接与SQL语句捆绑,故也被称为直接注入式攻击法。二是一种间接的攻击方法,它将恶意代码注入要在表中存储或者作为原书据存储的字符串。在存储的字符串中会连接到一个动态的SQL命令中,以执行一些恶意的SQL代码。

  注入过程的工作方式是提前终止文本字符串,然后追加一个新的命令。如以直接注入式攻击为例。就是在用户输入变量的时候,先用一个分号结束当前的语句。然后再插入一个恶意SQL语句即可。由于插入的命令可能在执行前追加其他字符串,因此攻击者常常用注释标记“—”来终止注入的字符串。执行时,系统会认为此后语句位注释,故后续的文本将被忽略,不背编译与执行。

  SQL注入式攻击的防治

普通用户与系统管理员用户的权限要有严格的区分。

强迫使用参数化语句。

加强对用户输入的验证。

多多使用数据库自带的安全参数。

必要的情况下使用专业的漏洞扫描工具来寻找可能被攻击的点。

在多层应用环境中,用户输入的所有数据都应该在验证之后才能被允许进入到可信区域。未通过验证过程的数据应被数据库拒绝,并向上一层返回一个错误信息。实现多层验证。对无目的的恶意用户采取的预防措施,对坚定的攻击者可能无效。更好的做法是在用户界面和所有跨信任边界的后续点上验证输入。如在客户端应用程序中验证数据可以防止简单的脚本注入。但是,如果下一层认为其输入已通过验证,则任何可以绕过客户端的恶意用户就可以不受限制地访问系统。故对于多层应用环境,在防止注入式攻击的时候,需要各层一起努力,在客户端与数据库端都要采用相应的措施来防治SQL语句的注入式攻击。

MySql的存储引擎的不同

单个索引、联合索引、主键索引

Mysql怎么分表,以及分表后如果想按条件分页查询怎么办

分表之后想让一个id多个表是自增的,效率实现

MySql的主从实时备份同步的配置,以及原理(从库读主库的binlog),读写分离。

索引的数据结构,B+树

数据库的锁

数据库事务的几种粒度
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据库 sql