简答题

1.MySQL常见的三种存储引擎(InnoDB、MyISAM、MEMORY)的区别(至少5点)?

l InnoDB存储引擎
InnoDB是事务型数据库的首选引擎,支持事务安全表(ACID),其它存储引擎都是非事务安全表,支持行锁定和外键,MySQL5.5以后默认使用InnoDB存储引擎。
InnoDB主要特性
为MySQL提供了具有提交、回滚和崩溃恢复能力的事务安全(ACID兼容)存储引擎。InnoDB锁定在行级并且也在 SELECT语句中提供一个类似Oracle的非锁定读。这些功能增加了多用户部署和性能。在SQL查询中,可以自由地将InnoDB类型的表和其他MySQL的表类型混合起来,甚至在同一个查询中也可以混合。

l MyISAM存储引擎
MyISAM基于ISAM存储引擎,并对其进行扩展。它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM拥有较高的插入、查询速度,但不支持事务,不支持外键。
MyISAM主要特性:
被大文件系统和操作系统支持。

当把删除和更新及插入操作混合使用的时候,动态尺寸的行产生更少碎片。这要通过合并相邻被删除的块,若下一个块被删除,就扩展到下一块自动完成。

每个MyISAM表最大索引数是64,这可以通过重新编译来改变。每个索引最大的列数是16。

最大的键长度是1000字节,这也可以通过编译来改变,对于键长度超过250字节的情况,一个超过1024字节的键将被用上。

BLOB和TEXT列可以被索引。

NULL被允许在索引的列中,这个值占每个键的0~1个字节。

所有数字键值以高字节优先被存储以允许一个更高的索引压缩。

MEMORY主要特性:

MEMORY表的每个表可以有多达32个索引,每个索引16列,以及500字节的最大键长度。

可以在一个MEMORY表中有非唯一键值。

MEMORY支持AUTO_INCREMENT列和对可包含NULL值的列的索引。

MEMORY表在所由客户端之间共享(就像其他任何非TEMPORARY表)。

MEMORY表内存被存储在内存中,内存是MEMORY表和服务器在查询处理时的空闲中,创建的内部表共享。

l 存储引擎的选择
在实际工作中,选择一个合适的存储引擎是一个比较复杂的问题。每种存储引擎都有自己的优缺点,不能笼统地说谁比谁好。

python学习之关系型数据库作业
InnoDB: 支持事务处理,支持外键,支持崩溃修复能力和并发控制。如果需要对事务的完整性要求比较高(比如银行),要求实现并发控制(比如售票),那选择InnoDB有很大的优势。如果需要频繁的更新、删除操作的数据库,也可以选择InnoDB,因为支持事务的提交(commit)和回滚(rollback)。
MyISAM: 插入数据快,空间和内存使用比较低。如果表主要是用于插入新记录和读出记录,那么选择MyISAM能实现处理高效率。如果应用的完整性、并发性要求比较低,也可以使用。
MEMORY: 所有的数据都在内存中,数据的处理速度快,但是安全性不高。如果需要很快的读写速度,对数据的安全性要求较低,可以选择MEMOEY。它对表的大小有要求,不能建立太大的表。所以,这类数据库只使用在相对较小的数据库表。
同一个数据库也可以使用多种存储引擎的表。如果一个表要求比较高的事务处理,可以选择InnoDB。这个数据库中可以将查询要求比较高的表选择MyISAM存储。如果该数据库需要一个用于查询的临时表,可以选择MEMORY存储引擎。
若要修改默认引擎,可以修改配置文件中的default-storage-engine。可以通过:show variables like 'default_storage_engine';查看当前数据库到默认引擎。命令:show engines和show variables like 'have%'可以列出当前数据库所支持到引擎。其中Value显示为disabled的记录表示数据库支持此引擎,而在数据库启动时被禁用。在MySQL5.1以后,INFORMATION_SCHEMA数据库中存在一个ENGINES的表,它提供的信息与show engines;语句完全一样,可以使用下面语句来查询哪些存储引擎支持事物处理:select engine from information_chema.engines where transactions ='yes';

可以通过engine关键字在创建或修改数据库时指定所使用到引擎。

在创建表的时候通过engine=...或type=...来指定所要使用的引擎。show table status from DBname来查看指定表的引擎。

2.数据库事务的四个特性及含义

ACID 表示事务的特性:原子性、一致性、隔离性和持久性。

原子性(Atomic):事务中各项操作,要么全做要么全不做,任何一项操作的失败都会
导致整个事务的失败;
一致性(Consistent):事务结束后系统状态是一致的;
隔离性(Isolated):并发执行的事务彼此无法看到对方的中间状态;
持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难性的失败。通
过日志和同步备份可以在故障发生后重建数据。

事务并发产生的问题:脏读、幻读、不可重复读。

脏读(Dirty Read): A 事务读取 B 事务尚未提交的数据并在此基础上操作,而 B 事务执
行回滚,那么 A 读取到的数据就是脏数据。
幻读(Phantom Read):事务 A 重新执行一个查询,返回一系列符合查询条件的行,发
现其中插入了被事务 B 提交的行。
不可重复读(Unrepeatable Read):事务 A 重新读取前面读取过的数据,发现该数据已
经被另一个已提交的事务 B 修改过了。

3.数据库三范式是什么?

第一范式:数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性存在传递函数依赖关系。

第二范式:完全依赖于主键,消除非主属性对主码的部分函数依赖

第三范式:每个非关键字列都独立于其他非关键字列,并依赖于关键字,第三范式指数据库中不能

4.数据库支持的SQL数据类型常用的有哪些?

1、INT (INTEGER)

INT (或INTEGER)数据类型存储从-2的31次方 (-2 ,147 ,483 ,648) 到2的31次方-1 (2 ,147 ,483,647) 之间的所有正负整数。每个INT 类型的数据按4 个字节存储,其中1 位表示整数值的正负号,其它31 位表示整数值的长度和大小。

2、SMALLINT

SMALLINT 数据类型存储从-2的15次方( -32, 768) 到2的15次方-1( 32 ,767 )之间的所有正负整数。每个SMALLINT 类型的数据占用2 个字节的存储空间,其中1 位表示整数值的正负号,其它15 位表示整数值的长度和大小。

二、 浮点数据类型:浮点数据类型用于存储十进制小数。浮点数值的数据在SQL Server 中采用上舍入(Round up 或称为只入不舍)方式进行存储。

1、REAL 数据类型

REAL数据类型可精确到第7 位小数,其范围为从-3.40E -38 到3.40E +38。 每个REAL类型的数据占用4 个字节的存储空间。

2、FLOAT

FLOAT数据类型可精确到第15 位小数,其范围为从-1.79E -308 到1.79E +308。 每个FLOAT 类型的数据占用8 个字节的存储空间。 FLOAT数据类型可写为FLOAT[ n ]的形式。n 指定FLOAT 数据的精度。n 为1到15 之间的整数值。

当n 取1 到7 时,实际上是定义了一个REAL 类型的数据,系统用4 个字节存储它;当n 取8 到15 时,系统认为其是FLOAT 类型,用8 个字节存储它。

三、 二进制数据类型

1、BINARY

BINARY 数据类型用于存储二进制数据。其定义形式为BINARY( n), n 表示数据的长度,取值为1 到8000 。在使用时必须指定BINARY 类型数据的大小,至少应为1 个字节。BINARY 类型数据占用n+4 个字节的存储空间。

在输入数据时必须在数据前加上字符“0X” 作为二进制标识,如:要输入“abc ”则应输入“0xabc ”。若输入的数据过长将会截掉其超出部分。若输入的数据位数为奇数,则会在起始符号“0X ”后添加一个0,如上述的“0xabc ”会被系统自动变为“0x0abc”。

2、VARBINARY

VARBINARY数据类型的定义形式为VARBINARY(n)。 它与BINARY 类型相似,n 的取值也为1 到8000, 若输入的数据过长,将会截掉其超出部分。

不同的是VARBINARY数据类型具有变动长度的特性,因为VARBINARY数据类型的存储长度为实际数值长度+4个字节。当BINARY数据类型允许NULL 值时,将被视为VARBINARY数据类型。

5.SQL数据类型varchar和char的区别?

1.CHAR的长度是固定的,而VARCHAR2的长度是可以变化的, 比如,存储字符串“abc",对于CHAR (10),表示你存储的字符将占10个字节(包括7个空字符),而同样的VARCHAR2 (10)则只占用3个字节的长度,10只是最大值,当你存储的字符小于10时,按实际长度存储。
2.CHAR的效率比VARCHAR2的效率稍高。

6.SQL 约束有哪几种并解释含义(eg:NOT NULL、UNIQUE等)?

7.数据库内连表、左连表、右连表有什么区别?

8.SQL语句查询时如何实现分页?

9.什么是SQL注入?

SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,***者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。

10.数据库怎么优化查询效率(参考解释)?

1). 储存引擎选择:如果数据表需要事务处理,应该考虑使用 InnoDB,因为它完全符合 ACID 特性。如果不需要事务处理,使用默认存储引擎 MyISAM 是比较明智的
2). 对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引
3). 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描
4). 应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描
5). 应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描
6). Update 语句,如果只更改 1、2 个字段,不要 Update 全部字段,否则频繁调用会引起明显的性能消耗,同时带来大量日志
7). 对于多张大数据量(这里几百条就算大了)的表 JOIN,要先分页再 JOIN,否则逻辑读会很高,性能很差。

二、SQL语句查询操作。

数据源: student.sql文件(上课时备份的数据库表信息)
1.创建数据库表employees, 包含的信息有:
属性名 属性含义 属性类型
emp_no 员工编号 整形、主键、自增
birth_date 出生年月 日期、非空
name 姓名 字符串、非空
gender 性别 整形、非空、1-男 2-女
hire_date 入职日期 日期、非空

MariaDB [Blog]> create table employees(emop_no int(4) primary key not null auto_increment);

MariaDB [Blog]> alter table employees add birth_date date not null;

MariaDB [Blog]> alter table employees add name varchar(20) not null;

MariaDB [Blog]> alter table employees add gender int(4) not null;

MariaDB [Blog]> alter table employees add hire_date date not null;

2.批量插入数据如下:
emp_no birth_date name gender hire_date
1 1996-10-10 高崎 女 2019-10-10
2 1995-10-10 刘欢 女 2019-6-10
3 1993-10-10 王佗 男 2019-1-10
4 1995-10-10 洪笙宁 男 2018-10-10
5 1991-2-1 张三 男 2017-10-10
MariaDB [Blog]> insert into employees values('1','1996-10-10','高崎','2','2019-10-10');

MariaDB [Blog]> insert into employees values('2','1995-10-10','刘欢','2','2019-6-10');

MariaDB [Blog]> insert into employees values('3','1993-10-10','洪笙宁','1','2019-1-10');

MariaDB [Blog]> insert into employees values('4','1995-10-10','王佗','1','2019-10-10');

MariaDB [Blog]> insert into employees values('5','1991-2-1','张三','1','2017-10-10');

MariaDB [Blog]> select * from employees;
+---------+------------+-----------+--------+------------+
| emop_no | birth_date | name | gender | hire_date |
+---------+------------+-----------+--------+------------+
| 1 | 1996-10-10 | 高崎 | 2 | 2019-10-10 |
| 2 | 1995-10-10 | 刘欢 | 2 | 2019-06-10 |
| 3 | 1993-10-10 | 王佗 | 1 | 2019-01-10 |
| 4 | 1995-10-10 | 洪笙宁 | 1 | 2019-10-10 |
| 5 | 1991-02-01 | 张三 | 1 | 2017-10-10 |
+---------+------------+-----------+--------+------------+
5 rows in set (0.00 sec)

3. 更新高崎的出生日期为1996-12-12.
MariaDB [Blog]> update employees set birth_date='1996-12-12' where emop_no=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

MariaDB [Blog]> select * from employees;
+---------+------------+-----------+--------+------------+
| emop_no | birth_date | name | gender | hire_date |
+---------+------------+-----------+--------+------------+
| 1 | 1996-12-12 | 高崎 | 2 | 2019-10-10 |
| 2 | 1995-10-10 | 刘欢 | 2 | 2019-06-10 |
| 3 | 1993-10-10 | 王佗 | 1 | 2019-01-10 |
| 4 | 1995-10-10 | 洪笙宁 | 1 | 2019-10-10 |
| 5 | 1991-02-01 | 张三 | 1 | 2017-10-10 |
+---------+------------+-----------+--------+------------+

4. 统计员工总人数。
MariaDB [Blog]> select count() from employees;
+----------+
| count(
) |
+----------+
| 5 |
+----------+

5. 统计入职时间超过2年的员工姓名.(拓展知识, 查阅资料)

MariaDB [Blog]>select * from employees where year(now())-year(hire_date)>2;
+---------+------------+--------+--------+------------+
| emop_no | birth_date | name | gender | hire_date |
+---------+------------+--------+--------+------------+
| 5 | 1991-02-01 | 张三 | 1 | 2017-10-10 |
+---------+------------+--------+--------+------------+

6. 查找最晚入职员工的所有信息
7.MariaDB [Blog]> select from employees where hire_date =(select max(hire_date) from employees);
8.+---------+------------+-----------+--------+------------+
9.| emop_no | birth_date | name | gender | hire_date |
10.+---------+------------+-----------+--------+------------+
11.| 1 | 1996-12-12 | 高崎 | 2 | 2019-10-10 |
12.| 4 | 1995-10-10 | 洪笙宁 | 1 | 2019-10-10 |
13.+---------+------------+-----------+--------+------------+
14. 查询最早入职员工的所有信息
MariaDB [Blog]> select
from employees order by hire_date limit 1;
+---------+------------+--------+--------+------------+
| emop_no | birth_date | name | gender | hire_date |
+---------+------------+--------+--------+------------+
| 5 | 1991-02-01 | 张三 | 1 | 2017-10-10 |
+---------+------------+--------+--------+------------+

15.查询成绩在85到90分之间的学生姓名、课程名和成绩。
| 陆君 | 95031 | 86.0 |
| 匡明 | 95031 | 88.0 |
MariaDB [Blog]> select distinct sname,cname,degree from students inner join scores on(students.sno=scores.sno) inner join courses on(scores.cno=courses.cno) where degree between 85 and 90;
+--------+-----------------+--------+
| sname | cname | degree |
+--------+-----------------+--------+
| 陆君 | 操作系统 | 86.0 |
| 匡明 | 计算机导论 | 88.0 |
| 李军 | 数据电路 | 85.0 |
+--------+-----------------+--------+

16.查询高等数学成绩最高的学生名和学生分数。
| 陆君 | 86.0 |
MariaDB [Blog]> select distinct sname,max(degree) from students inner join scores on(students.sno=scores.sno) inner join courses on(scores.cno=courses.cno) order by degree desc;
+--------+-------------+
| sname | max(degree) |
+--------+-------------+
| 陆君 | 92.0 |
+--------+-------------+

17.查询李军选修的课程名称。
| 计算机导论 |
| 数据电路 |

MariaDB [Blog]> select distinct sname,cname from students inner join scores on(students.sno=scores.sno) inner join courses on(scores.cno=courses.cno) where sname='李军';
+--------+-----------------+
| sname | cname |
+--------+-----------------+
| 李军 | 计算机导论 |
| 李军 | 数据电路 |
+--------+-----------------+