SQL基础语句

数据库面试常见题

一、SQL语言包括数据定义语言、数据操作语言、数据控制语言和事务控制语言
      1:DDL(Data Definition Language),是用于描述数据库中要存储的现实世界实体的语言。 
  • CREATE TABLE - 创建新表
  • ALTER TABLE - 变更(改变)数据库表
  • DROP TABLE - 删除表
  • CREATE INDEX - 创建索引(搜索键)
  • DROP INDEX - 删除索引

      2:DML(Data Manipulation Language),用户通过它可以实现对数据库的基本操作

        SELECT - 从数据库表中获取数据

        UPDATE - 更新数据库表中的数据

        DELETE - 从数据库表中删除数据

        INSERT - 向数据库表中插入数据

      3:DCL

        GRANT它可以把语句权限或者对象权限授予其他用户和角色。

        DENY它用于拒绝给当前数据库内的用户或者角色授予权限

        REVOKE它能够将以前在当前数据库内的用户或者角色上授予或拒绝的权限删除。

       4:TCL

        SAVEPOINT:“保存点”就像是一个标记,标记事务中的某个点以便将来可以回滚,用来将很长的事务划分为若干个较小的事务,它与回滚一起使用以回滚当前事务部分; 

        ROLLBACK:用于事务出错时回滚数据; 

        COMMIT:用于结束事务,对数据库做永久性修改,擦除事务中的所有保存点。COMMIT语句表示所有SQL语句均已执行完毕,事务成功结束,数据库处于一致状态; 

 

二、关系数据库设计范式:
     第一范式:无重复的列
     第二范式:非主属性完全依赖主键
     第三范式:每个非主属性都不传递依赖主键;一个数据库表中不包含已在其他表中包含的非主关键字信息,否则存在大量的数据冗余。
     BCNF:   消除主属性对关键字的部分和传递函数依赖
     第四范式:在一个没有单独列被定义为唯一的主键的表中,用多个列组合一起被定义为唯一主键。
 
 
三、SQL语句需要注意的地方:  
      主码约束 Primary Key    唯一性约束 Unique   非空值约束 NULL
      其中Primary Key与Unique的区别如下:primary key = unique +  not null

      1:作为Primary Key的域/域组不能为null,而Unique Key可以。 

      2:在一个表中只能有一个Primary Key,而多个Unique Key可以同时存在。

      distinct短语的作用范围是所有目标列(相当于保证查询结果的每一行数据都不重复,而不是每一个字段都不重复)
 
       未对查询结果分组,集函数将作用于整个查询结果
       对查询结果分组后,集函数将分别作用于每个组 
 
       Union all 和Union的区别与联系
       Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序; 
       Union All:对两个结果集进行并集操作,包括重复行,不进行排序; 
 
四、索引的工作原理与类别
     
       索引的优点:创建索引可以大大提高系统的性能。

       通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。

       可以大大加快数据的检索速度,这也是创建索引的最主要的原因。

       可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。

       在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。

       通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。 

      
       索引的代价:

       索引需要占用数据表以外的物理存储空间

       创建索引和维护索引要花费一定的时间

       当对表进行更新操作时,索引需要被重建,这样降低了数据的维护速度。

 
       索引的类别:
       普通索引:这是最基本的索引,它没有任何限制。
       唯一索引:与普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值(注意和主键不同)。如果是组合索引,则列值的组合必须唯一,创建方法和普通索引类似。
       主键索引:主键是一种唯一性索引,但它必须指定为“PRIMARY KEY”。
       全文索引:在MySQL中,全文索引的索引类型为FULLTEXT。全文索引可以在VARCHAR或者TEXT类型的列上创建。
       全文检索是对大数据文本进行索引,在建立的索引中对要查找的单词进行进行搜索,定位哪些文本数据包括要搜索的单词。
 
     
       SQL SERVER中聚集索引与非聚集索引的区别:见http://www.cnblogs.com/aspnethot/articles/1504082.html
       A)聚集索引,表数据按照索引的顺序来存储的。对于聚集索引,叶子结点即存储了真实的数据行,不再有另外单独的数据页。

       B)非聚集索引,表数据存储顺序与索引顺序无关。对于非聚集索引,叶结点包含索引字段值及指向数据页数据行的逻辑指针,该层紧邻数据页,其行数量与数据表行数据量一致。 

       在一张表上只能创建一个聚集索引,因为真实数据的物理顺序只可能是一种。如果一张表没有聚集索引,那么它被称为“堆集”(Heap)。这样的表中的数据行没有特定的顺序,所有的新行将被添加的表的末尾位置。 

 
五、数据库事务的四个特性以及隔离级别

       数据库事务transanction正确执行的四个基本要素。ACID,原子性(Atomicity)、一致性(Correspondence)、隔离性(Isolation)、持久性(Durability)。

       原子性:整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
       持久性:在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。

 

       数据库事务隔离级别:

       1:读取未提交

       READ UNCOMMITTED是限制性最弱的隔离级别,因为该级别忽略其他事务放置的锁。使用READ UNCOMMITTED级别执行的事务,可以读取尚未由其他事务提交的修改后的数据值,这些行为称为“脏”读。这是因为在Read Uncommitted级别下,读取数据不需要加S锁,这样就不会跟被修改的数据上的X锁冲突

       2:读取已提交

       READ COMMITTED(Nonrepeatable reads)是SQL Server默认的隔离级别。该级别通过指定语句不能读取其他事务已修改但是尚未提交的数据值,禁止执行脏读。在当前事务中的各个语句执行之间,其他事务仍可以修改、插入或删除数据,从而产生无法重复的读操作,或“影子”数据。比如,事务1读取了一行,事务2修改或者删除这一行并且提交。如果事务1想再一次读取这一行,它将获得修改后的数据或者发现这一样已经被删除,因此事务的第二次读取结果与第一次读取结果不同,因此也叫不可重复读。

       3:可重复读

      REPEATABLE READ是比READ COMMITTED限制性更强的隔离级别。该级别包括READ COMMITTED,并且另外指定了在当前事务提交之前,其他任何事务均不可以修改或删除当前事务已读取的数据。并发性低于 READ COMMITTED,因为已读数据的共享锁在整个事务期间持有,而不是在每个语句结束时释放。比如,事务1读取了一行,事务2想修改或者删除这一行并且提交,但是因为事务1尚未提交,数据行中有事务1的锁,事务2无法进行更新操作,因此事务2阻塞。如果这时候事务1想再一次读取这一行,它读取结果与第一次读取结果相同,因此叫可重复读

       4:串行读取

       SERIALIZABLE 是限制性最强的隔离级别,因为该级别锁定整个范围的键,并一直持有锁,直到事务完成。该级别包括REPEATABLE READ,并增加了在事务完成之前,其他事务不能向事务已读取的范围插入新行的限制。比如,事务1读取了一系列满足搜索条件的行。事务2在执行SQL statement产生一行或者多行满足事务1搜索条件的行时会冲突,则事务2回滚。这时事务1再次读取了一系列满足相同搜索条件的行,第二次读取的结果和第一次读取的结果相同。

 

     隔离级别与锁的关系:

  1. 在Read Uncommitted级别下,读操作不加S锁;
  2. 在Read Committed级别下,读操作需要加S锁,但是在语句执行完以后释放S锁;
  3. 在Repeatable Read级别下,读操作需要加S锁,但是在事务提交之前并不释放S锁,也就是必须等待事务执行完毕以后才释放S锁。
  4. 在Serialize级别下,会在Repeatable Read级别的基础上,添加一个范围锁。保证一个事务内的两次查询结果完全一样,而不会出现第一次查询结果是第二次查询结果的子集。

 

六、视图的作用

     * 简单性。

        看到的就是需要的。视图不仅可以简化用户对数据的理解,也可以简化他们的操作。那些被经常使用的查询可以被定义为视图,从而使得用户不必为以后的操作每次指定全部的条件。

     * 安全性。

       通过视图用户只能查询和修改他们所能见到的数据。数据库中的其它数据则既看不见也取不到。数据库授权命令可以使每个用户对数据库的检索限制到特定的数据库对象上,但不能授权到数据库特定行和特定的列上。通过视图,用户可以被限制在数据的不同子集上:

       使用权限可被限制在基表的行的子集上。

       使用权限可被限制在基表的列的子集上。

       使用权限可被限制在基表的行和列的子集上。

       使用权限可被限制在多个基表的连接所限定的行上。

       使用权限可被限制在基表中的数据的统计汇总上。

       使用权限可被限制在另一视图的一个子集上,或是一些视图和基表合并后的子集上。

    * 逻辑数据独立性。视图可帮助用户屏蔽真实表结构变化带来的影响。

 

        CREATE VIEW <视图名>[(列名组)]

                        AS <子查询>

        DROP VIEW <索引名>

 

      参考的博客地址:

      http://zhanghao007008.blog.163.com/blog/static/44874122200932293642494/

 

七、数据库的锁机制

      1.共享锁

      2.排他锁

      3.更新锁:因为共享锁与排他锁是不能共存的,排他锁只能等共享锁释放掉才可以。所以为了避免死锁,引入了更新锁机制。一个事物只能有一个更新锁。更新锁其实为了预定排它锁而存在,更新锁与排它锁也是不能共存的,需要将更新锁升级为排他锁。

 

      参考博客地址:

      http://www.cnblogs.com/zhouqianhua/archive/2011/04/15/2017049.html

 

八、存储过程

      一、存储过程与函数的区别:

  1.一般来说,存储过程实现的功能要复杂一点,而函数的实现的功能针对性比较强。

  2.对于存储过程来说可以返回参数(output),而函数只能返回值或者表对象。

  3.存储过程一般是作为一个独立的部分来执行,而函数可以作为查询语句的一个部分来调用,由于函数可以返回一个表对象,因此它可以在查询语句中位于FROM关键字的后面。

 

      二、存储过程的优点:

  1.执行速度更快 – 在数据库中保存的存储过程语句都是编译过的

  2.允许模块化程序设计 – 类似方法的复用

  3.提高系统安全性 – 防止SQL注入(攻击者把SQL命令插入到Web表单的输入域或者页面请求的查询字符中,欺骗服务器执行恶意的SQL命令)

  4.减少网络流通量 – 只要传输存储过程的名称,在服务器上运行

 

      三、定义存储过程语法,"["   里面的内容表示可选项

  create proc 存储过程名

  @参数1        数据类型 [=默认值] [output],

  @参数2        数据类型 [=默认值] [output],

  ...

  as

  SQL语句

 

九、触发器

      触发器可以分为语句级触发器和行级触发器。简单的说就是语句级的触发器可以在某些语句执行前或执行后被触发。而行级触发器则是在定义触发的表中的行数据改变时就会被触发一次。

      触发器是一种特殊的存储过程。一般的存储过程是通过存储过程名直接调用,而触发器主要是通过事件(增、删、改)进行触发而被执行的,在表中数据发生变化时自动强制执行。

  常见的触发器有两种:after(for)、instead of,用于insert、update、delete事件。

  after(for)         表示执行代码后,执行触发器

  instead of        表示执行代码前,用已经写好的触发器代替你的操作

 

      触发器语法:

      create trigger 触发器的名字   on 操作表

                for|after         instead of

                update|insert|delete

      as

                SQL语句

 

      存储过程与触发器的区别:

      触发器与存储过程非常相似,触发器也是SQL语句集,两者唯一的区别是触发器不能用EXECUTE语句调用,而是在用户执行事务语句时自动触发(激活)执行。触发器是在一个修改了指定表中的数据时执行的存储过程。通常通过创建触发器来强制实现不同表中的逻辑相关数据的引用完整性和一致性。触发器不同于存储过程,触发器主要是通过事件执行触发而被执行的,而存储过程可以通过存储过程名称名字而直接调用。当对某一表进行诸如UPDATE、INSERT、DELETE这些操作时,会自动执行触发器所定义的SQL语句,从而确保对数据的处理必须符合这些SQL语句所定义的规则。

 

十、数据库引擎

     参考博客地址:http://www.cnblogs.com/sopc-mc/archive/2011/11/01/2232212.html

      Innodb引擎提供了对数据库ACID事务的支持,并且实现了SQL标准的四种隔离级别。该引擎还提供了行级锁和外键约束,它的设计目标是处理大容量数据库系统,它本身其实就是基于MySQL后台的完整数据库系统,MySQL运行时Innodb会在内存中建立缓冲池,用于缓冲数据和索引。但是该引擎不支持FULLTEXT类型的索引,而且它没有保存表的行数,当SELECT COUNT(*) FROM TABLE时需要扫描全表。当需要使用数据库事务时,该引擎当然是首选。由于锁的粒度更小,写操作不会锁定全表,所以在并发较高时,使用Innodb引擎会提升效率。但是使用行级锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表。

 

      MyIASM是MySQL默认的引擎,但是它没有提供对数据库事务的支持,也不支持行级锁和外键,因此当INSERT(插入)或UPDATE(更新)数据时即写操作需要锁定整个表,效率便会低一些。不过和Innodb不同,MyIASM中存储了表的行数,于是SELECT COUNT(*) FROM TABLE时只需要直接读取已经保存好的值而不需要进行全表扫描。如果表的读操作远远多于写操作且不需要数据库事务的支持,那么MyIASM也是很好的选择。

 

 

十一、关系数据库与非关系数据库的区别

     参考博客地址:http://blog.csdn.net/robinjwong/article/details/18502195/

     

      关系型数据库的最大特点就是事务的一致性:传统的关系型数据库读写操作都是事务的,具有ACID的特点,这个特性使得关系型数据库可以用于几乎所有对一致性有要求的系统中,如典型的银行系统。

      但是,在网页应用中,尤其是SNS应用中,一致性却不是显得那么重要,用户A看到的内容和用户B看到同一用户C内容更新不一致是可以容忍的,或者说,两个人看到同一好友的数据更新的时间差那么几秒是可以容忍的,因此,关系型数据库的最大特点在这里已经无用武之地,起码不是那么重要了。

      相反地,关系型数据库为了维护一致性所付出的巨大代价就是其读写性能比较差,而像微博、facebook这类SNS的应用,对并发读写能力要求极高,关系型数据库已经无法应付(在读方面,传统上为了克服关系型数据库缺陷,提高性能,都是增加一级memcache来静态化网页,而在SNS中,变化太快,memchache已经无能为力了),因此,必须用新的一种数据结构存储来代替关系数据库。

      关系数据库的另一个特点就是其具有固定的表结构,因此,其扩展性极差,而在SNS中,系统的升级,功能的增加,往往意味着数据结构巨大变动,这一点关系型数据库也难以应付,需要新的结构化数据存储。

      于是,非关系型数据库应运而生,由于不可能用一种数据结构化存储应付所有的新的需求,因此,非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合。

     

     非关系型数据库的分类

     

  • 面向高性能并发读写的key-value数据库:key-value数据库的主要特点即使具有极高的并发读写性能,Redis,Tokyo Cabinet,Flare就是这类的代表
  • 面向海量数据访问的面向文档数据库:这类数据库的特点是,可以在海量的数据中快速的查询数据,典型代表为MongoDB以及CouchDB
  • 面向可扩展性的分布式数据库:这类数据库想解决的问题就是传统数据库存在可扩展性上的缺陷,这类数据库可以适应数据量的增加以及数据结构的变化

 

 

十二、数据库优化

     参考博客地址:http://blog.sina.com.cn/s/blog_76c0a1c50101d0gq.html     

     常见的数据库优化方法:索引(数据库),缓存,分表,分库,sql优化。
 
     索引:创建索引一般有以下两个目的:维护被索引列的唯一性和提供快速访问表中数据的策略。索引有助于提高检索性能,但过多或不当的索引也会导致系统低 效。因为用户在表中每加进一个索引,数据库就要做更多的工作。过多的索引甚至会导致索引碎片。 
 
     分表:针对每个时间周期产生大量的数据,可以考虑采用一定的策略将数据存到多个数据表中。
 
     分库:就是将系统按照模块相关的特征分布到不同的数据中,以提高系统整体负载能力。
 
     sql优化:
     1.in 和 not in 也要慎用,因为IN会使系统无法使用索引,而只能直接搜索表中的数据。如:
               select id from t where num in(1,2,3)对于连续的数值,能用 between 就不要用 in 了:
               select id from t where num between 1 and 3
 
     2.当判断真假是,如果带and 或者 or :(当存在 “where 条件1 and 条件2” 时,数据库先执行右边的语句)
               and尽量把假的放到右边(一个为假就为假)  Or尽量把为真的放到右边(一个为真就为真)
 
     3.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。 如:
               SELECT * FROM T1 WHERE F1/2=100 
               应改为: SELECT * FROM T1 WHERE F1=100*2
               SELECT * FROM RECORD WHERE SUBSTRING(CARD_NO,1,4)=’5378’ 
               应改为: SELECT * FROM RECORD WHERE CARD_NO LIKE ‘5378%’
               SELECT member_number, first_name, last_name FROM members WHERE DATEDIFF(yy,datofbirth,GETDATE()) > 21 
               应改为: SELECT member_number, first_name, last_name FROM members WHERE dateofbirth < DATEADD(yy,-21,GETDATE()) 
               即:任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时 要尽可能将操作移至等号右边
 
     4.很多时候用 exists是一个好的选择:
              如果你想校验表里是否存在某条纪录,不要用count(*)那样效率很低,而且浪费服务 器资源。可以用EXISTS代替。如: 
              IF (SELECT COUNT(*) FROM table_name WHERE column_name = 'xxx') 
              可以写成: IF EXISTS (SELECT * FROM table_name WHERE column_name = 'xxx')
 
     5.充分利用连接条件,在某种情况下,两个表之间可能不只一个的连接条件,这时在 WHERE 子句中将 连接条件完整的写上,有可能大大提高查询速度。 
              SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO 
              SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO AND A.ACCOUNT_NO=B.ACCOUNT_NO 
              第二句将比第一句执行快得多。
 
     6.使用视图加速查询 
              把表的一个子集进行排序并创建视图,有时能加速查询。它有助于避免多重排序操作,而且在其他方面还能简化优化器的工作。
              视图中的行要比主表中的行少,而且物理顺序就是所要求的顺序,减少了磁盘I/O,所以查询工作量可以得到大幅减少。
 
     EXISTS语法是说说exists后面的语句执行的结果是不是有记录,只产生逻辑真值‘true’与逻辑假值‘False’。由EXISTS引出的子查询,其目标列表达式通常都用*(用null也可以),因为带有EXISTS的子查询只返回真值或假值,给出列名没有实际意义。
 

十三、分页查询

     参考博客地址:http://blog.csdn.net/guyong1018/article/details/2183057

     MySQL数据库实现分页比较简单,提供了LIMIT函数。一般只需要直接写到sql语句后面就行了。

     LIMIT子句可以用来限制由SELECT语句返回过来的数据数量,它有一个或两个参数,
     如果给出两个参数, 第一个参数指定返回的第一行在所有数据中的位置,从0开始(注意不是1),第二个参数指定最多返回行数。例如:
     select * from table WHERE … LIMIT 10; #返回前10行
     select * from table WHERE … LIMIT 0,10; #返回前10行
     select * from table WHERE … LIMIT 10,20; #返回第10-20行数据
 
posted @ 2015-08-21 20:47  cxm_hy  阅读(307)  评论(0编辑  收藏  举报