一、 Mysql
1. SQL 的 select 语句完整的执行顺序
SQL Select 语句完整的执行顺序:
1、 from 子句组装来自不同数据源的数据;
2、 where 子句基于指定的条件对记录行进行筛选;
3、 group by 子句将数据划分为多个分组;
4、使用聚集函数进行计算;
5、使用 having 子句筛选分组;
6、计算所有的表达式;
7、 select 的字段;
8、使用 order by 对结果集进行排序。
SQL 语言不同于其他编程语言的最明显特征是处理代码的顺序。在大多数据库语言中,代码按编码顺序被处理。但在 SQL 语句中,第一个被处理的子句式 FROM,而不是第一出现的 SELECT。 SQL 查询处理的步骤序号:
(1) FROM <left_table>
(2) <join_type> JOIN <right_table>
(3) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) WITH {CUBE | ROLLUP}
(7) HAVING <having_condition>
(8) SELECT
(9) DISTINCT
(9) ORDER BY <order_by_list>
(10) <TOP_specification> <select_list>
以上每个步骤都会产生一个虚拟表,该虚拟表被用作下一个步骤的输入。这些虚拟表对调用者(客户端应用程序或者外部查询)不可用。只有最后一步生成的表才会会给调用者。如果没有在查询中指定某一个子句,将跳过相应的步骤。
逻辑查询处理阶段简介:
1、 FROM:对 FROM 子句中的前两个表执行笛卡尔积(交叉联接),生成虚拟表 VT1。
2、 ON:对 VT1 应用 ON 筛选器,只有那些使为真才被插入到 TV2。
3、 OUTER (JOIN):如果指定了 OUTER JOIN(相对于 CROSS JOIN 或 INNER JOIN),保留表中未找到
匹配的行将作为外部行添加到 VT2,生成 TV3。如果 FROM 子句包含两个以上的表,则对上一个联接生成的
结果表和下一个表重复执行步骤 1 到步骤 3,直到处理完所有的表位置。
4、 WHERE:对 TV3 应用 WHERE 筛选器,只有使为 true 的行才插入 TV4。
5、 GROUP BY:按 GROUP BY 子句中的列列表对 TV4 中的行进行分组,生成 TV5。
6、 CUTE|ROLLUP:把超组插入 VT5,生成 VT6。
7、 HAVING:对 VT6 应用 HAVING 筛选器,只有使为 true 的组插入到 VT7。
8、 SELECT:处理 SELECT 列表,产生 VT8。
9、 DISTINCT:将重复的行从 VT8 中删除,产品 VT9。
10、 ORDER BY:将 VT9 中的行按 ORDER BY 子句中的列列表顺序,生成一个游标(VC10)。
11、 TOP:从 VC10 的开始处选择指定数量或比例的行,生成表 TV11,并返回给调用者。
where 子句中的条件书写顺序
2. SQL 之聚合函数
聚合函数是对一组值进行计算并返回单一的值的函数,它经常与 select 语句中的 group by 子句一同使用。
a. avg():返回的是指定组中的平均值,空值被忽略。
b. count():返回的是指定组中的项目个数。
c. max():返回指定数据中的最大值。
d. min():返回指定数据中的最小值。
e. sum():返回指定数据的和,只能用于数字列,空值忽略。
f. group by():对数据进行分组,对执行完 group by 之后的组进行聚合函数的运算, 计算每一组的值。
最后用having去掉不符合条件的组,having子句中的每一个元素必须出现在select列表中(只针对于mysql)。
3. SQL 之连接查询(左连接和右连接的区别)
外连接:
左连接(左外连接):以左表作为基准进行查询,左表数据会全部显示出来,右表如果和左表匹配的数据则显示相应字段的数据,如果不匹配则显示为 null。
右连接(右外连接):以右表作为基准进行查询,右表数据会全部显示出来,左表如果和右表匹配的数据则显示相应字段的数据,如果不匹配则显示为 null。
全连接:先以左表进行左外连接,再以右表进行右外连接。
内连接:显示表之间有连接匹配的所有行。
4. SQL 之 sql 注入
通过在 Web 表单中输入(恶意) SQL 语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行 SQL 语句。举例:当执行的 sql 为 select * from user where username = “admin”or “a” =“a” 时, sql 语句恒成立,参数 admin 毫无意义。
防止 sql 注入的方式:
1. 预编译语句:如, select * from user where username = ?, sql 语句语义不会发生改变, sql 语句中变量用?表示,即使传递参数时为“admin or ‘a’ = ‘a’ ”,也会把这整体当做一个字符创去查询。
2. Mybatis 框架中的 mapper 方式中的 # 也能很大程度的防止 sql 注入($无法防止 sql 注入)。
5. Mysql 性能优化
1、 当只要一行数据时使用 limit 1
查询时如果已知会得到一条数据,这种情况下加上 limit 1 会增加性能。因为 mysql 数据库引
擎会在找到一条结果停止搜索,而不是继续查询下一条是否符合标准直到所有记录查询完毕。
2、 选择正确的数据库引擎
Mysql 中有两个引擎 MyISAM 和 InnoDB,每个引擎有利有弊。
MyISAM 适用于一些大量查询的应用,但对于有大量写功能的应用不是很好。甚至你只需要update 一个字段整个表都会被锁起来。而别的进程就算是读操作也不行要等到当前 update 操作完成之后才能继续进行。另外, MyISAM 对于 select count(*)这类操作是超级快的。
InnoDB 的趋势会是一个非常复杂的存储引擎,对于一些小的应用会比 MyISAM 还慢,但是支持“行锁”,所以在写操作比较多的时候会比较优秀。并且,它支持很多的高级应用,例如:事物。
3. 用 not exists 代替 not in
Not exists 用到了连接能够发挥已经建立好的索引的作用, not in 不能使用索引。 Not in 是最慢的方式要同每条记录比较,在数据量比较大的操作红不建议使用这种方式。
4. 对操作符的优化,尽量不采用不利于索引的操作符
如: in not in is null is not null <> 等
某个字段总要拿来搜索,为其建立索引:
Mysql 中可以利用 alter table 语句来为表中的字段添加索引,语法为: alter table 表明
add index (字段名);
6. 必看 sql 面试题(学生表_课程表_成绩表_教师表)
给大家推荐一篇非常好的博客,该博客中收集了最常见的 Mysql 常见面试题和笔试题。
博客链接:
7. Mysql 数据库架构图(2017-11-25-wzz)
MyISAM 和 InnoDB 是最常见的两种存储引擎,特点如下。
MyISAM 存储引擎
MyISAM 是 MySQL 官方提供默认的存储引擎,其特点是不支持事务、表锁和全文索引,对于一些 OLAP(联机分析处理)系统,操作速度快。
每个 MyISAM 在磁盘上存储成三个文件。文件名都和表名相同,扩展名分别是.frm(存储表定义)、.MYD (MYData,存储数据)、 .MYI (MYIndex,存储索引)。这里特别要注意的是 MyISAM 不缓存数据文件,只缓存索引文件。
InnoDB 存储引擎
InnoDB 存储引擎支持事务,主要面向 OLTP(联机事务处理过程)方面的应用,其特点是行锁设置、支持外键,并支持类似于 Oracle 的非锁定读,即默认情况下读不产生锁。 InnoDB 将数据放在一个逻辑表空间中(类似 Oracle)。
InnoDB 通过多版本并发控制来获得高并发性,实现了 ANSI 标准的 4 种隔离级别,默认为 Repeatable,使用一种被称为 next-key locking 的策略避免幻读。
对于表中数据的存储, InnoDB 采用类似 Oracle 索引组织表 Clustered 的方式进行存储。
InnoDB 存储引擎提供了具有提交、回滚和崩溃恢复能力的事务安全。但是对比 Myisam 的存储引擎, InnoDB 写的处理效率差一些并且会占用更多的磁盘空间以保留数据和索引。
InnoDB 体系架构
8. Mysql 架构器中各个模块都是什么?(2017-11-25-wzz)
(1)、连接管理与安全验证是什么?
每个客户端都会建立一个与服务器连接的线程,服务器会有一个线程池来管理这些 连接;如果客户端需要连接到 MYSQL 数据库还需要进行验证,包括用户名、密码、 主机信息等。
(2)、解析器是什么?
解析器的作用主要是分析查询语句,最终生成解析树;首先解析器会对查询语句的语法进行分析,分析语法是否有问题。还有解析器会查询缓存,如果在缓存中有对应的语句,就返回查询结果不进行接下来的优化执行操作。前提是缓存中的数据没有被修改,当然如果被修改了也会被清出缓存。
(3)、优化器怎么用?
优化器的作用主要是对查询语句进行优化操作,包括选择合适的索引,数据的读取方式,包括获取查询的开销信息,统计信息等,这也是为什么图中会有优化器指向存储引擎的箭头。之前在别的文章没有看到优化器跟存储引擎之间的关系,在这里我个人的理解是因为优化器需要通过存储引擎获取查询的大致数据和统计信息。
(4)、执行器是什么?
执行器包括执行查询语句,返回查询结果,生成执行计划包括与存储引擎的一些处理操作。
9. Mysql 存储引擎有哪些?(2017-11-25-wzz)
(1)、 InnoDB 存储引擎
InnoDB 是事务型数据库的首选引擎,支持事务安全表(ACID),支持行锁定和外键, InnoDB 是默认的 MySQL引擎。
(2)、 MyISAM 存储引擎
MyISAM 基于 ISAM 存储引擎,并对其进行扩展。它是在 Web、数据仓储和其他应用环境下最常使用的存储引擎之一。 MyISAM 拥有较高的插入、查询速度,但不支持事物。
(3)、 MEMORY 存储引擎
MEMORY 存储引擎将表中的数据存储到内存中,未查询和引用其他表数据提供快速访问。
(4)、 NDB 存储引擎
DB 存储引擎是一个集群存储引擎,类似于 Oracle 的 RAC,但它是 Share Nothing 的架构,因此能提供更高级别的高可用性和可扩展性。 NDB 的特点是数据全部放在内存中,因此通过主键查找非常快。
关于 NDB,有一个问题需要注意,它的连接(join)操作是在 MySQL 数据库层完成,不是在存储引擎层完成,这意味着,复杂的 join 操作需要巨大的网络开销,查询速度会很慢。
(5) 、 Memory (Heap) 存储引擎
Memory 存储引擎(之前称为 Heap)将表中数据存放在内存中,如果数据库重启或崩溃,数据丢失,因此它非常适合存储临时数据。
(6) 、 Archive 存储引擎
正如其名称所示, Archive 非常适合存储归档数据,如日志信息。它只支持 INSERT 和 SELECT 操作,其设计的主要目的是提供高速的插入和压缩功能。
(7) 、 Federated 存储引擎
Federated 存储引擎不存放数据,它至少指向一台远程 MySQL 数据库服务器上的表,非常类似于 Oracle 的透明网关。
(8)、 Maria 存储引擎
Maria 存储引擎是新开发的引擎,其设计目标是用来取代原有的 MyISAM 存储引擎,从而成为 MySQL 默认的存储引擎。
上述引擎中, InnoDB 是事务安全的存储引擎,设计上借鉴了很多 Oracle 的架构思想,一般而言,在 OLTP应用中, InnoDB 应该作为核心应用表的首先存储引擎。 InnoDB 是由第三方的 Innobase Oy 公司开发,现已被Oracle 收购,创始人是 Heikki Tuuri,芬兰赫尔辛基人,和著名的 Linux 创始人 Linus 是校友。
10. MySQL 事务介绍(2017-11-25-wzz)
MySQL 和其它的数据库产品有一个很大的不同就是事务由存储引擎所决定,例如 MYISAM,MEMORY,ARCHIVE都不支持事务,事务就是为了解决一组查询要么全部执行成功,要么全部执行失败。
MySQL 事务默认是采取自动提交的模式,除非显示开始一个事务。
SHOW VARIABLES LIKE 'AUTOCOMMIT';
修改自动提交模式, 0=OFF,1=ON
注意:修改自动提交对非事务类型的表是无效的,因为它们本身就没有提交和回滚的概念,还有一些命令是会强制自动提交的,比如 DLL 命令、 lock tables 等。
SET AUTOCOMMIT=OFF 或 SET AUTOCOMMIT=0
10.1 事务的四大特征是什么?
数据库事务 transanction 正确执行的四个基本要素。 ACID,原子性(Atomicity)、一致性(Correspondence)、隔离性(Isolation)、持久性(Durability)。
(1)原子性:整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
(2)一致性:在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
(3)隔离性:隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行 相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆, 必须串行化或序列化请 求,使得在同一时间仅有一个请求用于同一数据。
(4)持久性:在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
10.2 Mysql 中四种隔离级别分别是什么?
是 | 是 | 是 |
否 | 是 | 是 |
否 | 否 | 是 |
否 | 否 | 否 |
读未提交(READ UNCOMMITTED) :未提交读隔离级别也叫读脏,就是事务可以读取其它事务未提交的数据。
读已提交(READ COMMITTED) :在其它数据库系统比如 SQL Server 默认的隔离级别就是提交读,已提交读隔离级别就是在事务未提交之前所做的修改其它事务是不可见的。
可重复读(REPEATABLE READ) :保证同一个事务中的多次相同的查询的结果是一致的,比如一个事务一开始查询了一条记录然后过了几秒钟又执行了相同的查询,保证两次查询的结果是相同的,可重复读也是 mysql 的默认隔离级别。
可串行化(SERIALIZABLE) :可串行化就是保证读取的范围内没有新的数据插入,比如事务第一次查询得到某个范围的数据,第二次查询也同样得到了相同范围的数据,中间没有新的数据插入到该范围中。
11. MySQL 怎么创建存储过程(2017-11-25-wzz)
MySQL 存储过程是从 MySQL5.0 开始增加的新功能。存储过程的优点有一箩筐。不过最主要的还是执行效率和SQL 代码封装。特别是 SQL 代码封装功能,如果没有存储过程,在外部程序访问数据库时,要组织很多 SQL 语句。
特别是业务逻辑复杂的时候,一大堆的 SQL 和条件夹杂在代码中,让人不寒而栗。现在有了 MySQL 存储过程,业务逻辑可以封装存储过程中,这样不仅容易维护,而且执行效率也高。
一、创建 MySQL 存储过程
下面代码创建了一个叫 pr_add 的 MySQL 存储过程,这个 MySQL 存储过程有两个 int 类型的输入参数“a”、“b”,返回这两个参数的和。
1) drop procedure if exists pr_add; (备注:如果存在 pr_add 的存储过程,则先删掉)
2)计算两个数之和(备注:实现计算两个整数之和的功能)
create procedure pr_add ( a int, b int ) begin declare c int;
if a is null then set a = 0;
end if;
if b is null then set b = 0;
end if;
set c = a + b;
select c as sum;
二、 调用 MySQL 存储过程
call pr_add(10, 20);
12. MySQL 触发器怎么写?(2017-11-25-wzz)
MySQL 包含对触发器的支持。触发器是一种与表操作有关的数据库对象,当触发器所在表上出现指定事件时,将
调用该对象,即表的操作事件触发表上的触发器的执行。
在 MySQL 中,创建触发器语法如下:
CREATE TRIGGER trigger_name
trigger_time
trigger_event ON tbl_name
FOR EACH ROW
trigger_stmt
其中:
trigger_name:标识触发器名称,用户自行指定;
trigger_time:标识触发时机,取值为 BEFORE 或 AFTER;
trigger_event:标识触发事件,取值为 INSERT、 UPDATE 或 DELETE;
tbl_name:标识建立触发器的表名,即在哪张表上建立触发器;
trigger_stmt:触发器程序体,可以是一句 SQL 语句,或者用 BEGIN 和 END 包含的多条语句。
由此可见,可以建立 6 种触发器,即: BEFORE INSERT、 BEFORE UPDATE、 BEFORE DELETE、 AFTER INSERT、
AFTER UPDATE、 AFTER DELETE。
另外有一个限制是不能同时在一个表上建立 2 个相同类型的触发器,因此在一个表上最多建立 6 个触发器。
假设系统中有两个表:
1)班级表 class(班级号 classID, 班内学生数 stuCount)
2)学生表 student(学号 stuID, 所属班级号 classID)
要创建触发器来使班级表中的班内学生数随着学生的添加自动更新,代码如下:
create trigger tri_stuInsert after insert
on student for each row
begin
declare c int;
set c = (select stuCount from class where classID=new.classID);
update class set stuCount = c + 1 where classID = new.classID;
查看触发器:
和查看数据库(show databases;)查看表格(show tables;)一样,查看触发器的语法如下:
SHOW TRIGGERS [FROM schema_name];
其中, schema_name 即 Schema 的名称,在 MySQL 中 Schema 和 Database 是一样的,也就是说,可以指定数据库名,这样就不必先“USE database_name;”了。
删除触发器:
和删除数据库、删除表格一样,删除触发器的语法如下:
DROP TRIGGER [IF EXISTS] [schema_name.]trigger_name
13. MySQL 语句优化(2017-11-26-wzz)
13.1 where 子句中可以对字段进行 null 值判断吗?
可以,比如 select id from t where num is null 这样的 sql 也是可以的。但是最好不要给数据库留 NULL,尽可能的使用 NOT NULL 填充数据库。不要以为 NULL 不需要空间,比如: char(100) 型,在字段建立时,空间就固定了,不管是否插入值(NULL 也包含在内),都是占用 100 个字符的空间的,如果是 varchar 这样的变长字段, null 不占用空间。可以在 num 上设置默认值 0,确保表中 num 列没有 null 值,然后这样查询: select id from t where num= 0。
13.2 select * from admin left join log on admin.admin_id = log.admin_id where
log.admin_id>10 如何优化?
优化为: select * from (select * from admin where admin_id>10) T1 lef join log on T1.admin_id =log.admin_id。
使用 JOIN 时候,应该用小的结果驱动大的结果(left join 左边表结果尽量小如果有条件应该放到左边先处理,right join 同理反向),同时尽量把牵涉到多表联合的查询拆分多个 query(多个连表查询效率低,容易到之后锁表和阻塞)。
13.3 limit 的基数比较大时使用 between
例如: select * from admin order by admin_id limit 100000,10
优化为: select * from admin where admin_id between 100000 and 100010 order by admin_id。
13.4 尽量避免在列上做运算,这样导致索引失效
例如: select * from admin where year(admin_time)>2014
优化为: select * from admin where admin_time> '2014-01-01′
14. MySQL 中文乱码问题完美解决方案(2017-12-07-lwl)
解决乱码的核心思想是统一编码。我们在使用 MySQL 建数据库和建表时应尽量使用统一的编码,强烈推荐的是 utf8 编码,因为该编码几乎可以兼容世界上所有的字符。
数据库在安装的时候可以设置默认编码,在安装时就一定要设置为 utf8 编码。设置之后再创建的数据库和表如果不指定编码,默认都会使用 utf8 编码,省去了很多麻烦。
数据库软件安装好之后可以通过如下命令查看默认编码:
1、 查询数据库软件使用的默认编码格式
show variables like “%colla%”;
show varables like “%char%”
其中 collation,代表了字符串排序(比较)的规则,如果值是 utf8_general_ci,代表使用 utf8 字符集大小写
不敏感的自然方式比较。
如果 character_set 的值不为 utf8,那么可以使用如下命令修改为 utf8。
2、 修改数据库默认编码为 utf8
SET character_set_client='utf8';
SET character_set_connection='utf8';
SET character_set_results='utf8';
如果不想设置数据库软件的全局默认编码,也可以单独修改或者设置某个具体数据库的编码也可以单独修改或设置某个数据库中某个表的编码。
3、 创建数据库的时候指定使用 utf8 编码
CREATE DATABASE `test`
CHARACTER SET 'utf8'
COLLATE 'utf8_general_ci';
4、 创建表的时候指定使用 utf8 编码
CREATE TABLE `database_user` (
`ID` varchar(40) NOT NULL default '',
`UserID` varchar(40) NOT NULL default '',
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
如果数据库已经创建好了,可以使用 show database 数据库名;和 show create table 表名;查看一下数据库和表的字符集是否为 utf8 , 如果不是则在命令行下面可以用如下命令,将数据库和表编码修改为 utf8.
5、 修改具体某数据库或表的编码
ALTER DATABASE `db_name` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
ALTER TABLE `tb_name` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
15. 如何提高 MySQL 的安全性(2017-12-8-lwl)
1.如果 MySQL 客户端和服务器端的连接需要跨越并通过不可信任的网络,那么需要使用 ssh 隧道来加密该连接的通信。
2.使用 set password 语句来修改用户的密码,先“mysql -u root”登陆数据库系统,然后“mysql> update mysql.user set password=password(’ newpwd’ )”,最后执行“flush privileges”。
3.MySQL 需要提防的攻击有,防偷听、篡改、回放、拒绝服务等,不涉及可用性和容错方面。对所有的连接、查询、其他操作使用基于 ACL(ACL(访问控制列表)是一种路由器配置和控制网络访问的一种有力的工具,它可控制路由器应该允许或拒绝数据包通过,可监控流量,可自上向下检查网络的安全性,可检查和过滤数据和限制不必要的路由更新,因此让网络资源节约成本的 ACL 配置技术在生活中越来越广泛应用。) 即访问控制列表的安全措施来完成。
4.设置除了 root 用户外的其他任何用户不允许访问 mysql 主数据库中的 user 表;
5.使用 grant 和 revoke 语句来进行用户访问控制的工作;
6.不要使用明文密码,而是使用 md5()和 sha1()等单向的哈系函数来设置密码;
7.不要选用字典中的字来做密码;
8.采用防火墙可以去掉 50%的外部危险,让数据库系统躲在防火墙后面工作,或放置在 DMZ(DMZ 是英文“demilitarized zone”的缩写,隔离区,它是为了解决安装防火墙后外部网络的访问用户不能访问内部网络服务器的问题,而设立的一个非安全系统与安全系统之间的缓冲区。) 区域中;
9.从因特网上用 nmap 来扫描 3306 端口,也可用 telnet server_host 3306 的方法测试,不允许从非信任网络中访问数据库服务器的 3306 号 tcp 端口,需要在防火墙或路由器上做设定;
10.服务端要对 SQL 进行预编译,避免 SQL 注入攻击, 例如 where id=234,别人却输入 where id=234 or 1=1。
11.在传递数据给 mysql 时检查一下大小;
12.应用程序连接到数据库时应该使用一般的用户帐号,开放少数必要的权限给该用户;
13.学会使用 tcpdump 和 strings 工具来查看传输数据的安全性,例如 tcpdump -l -i eth0 -w -src or dst port 3306 strings。以普通用户来启动 mysql 数据库服务;
14.确信在 mysql 目录中只有启动数据库服务的用户才可以对文件有读和写的权限;
15.不许将 process 或 super 权限付给非管理用户,该 mysqladmin processlist 可以列举出当前执行的查询文本;super 权限可用于切断客户端连接、改变服务器运行参数状态、控制拷贝复制数据库的服务器;
16.如果不相信 dns 服务公司的服务,可以在主机名称允许表中只设置 ip 数字地址;
17.使用 max_user_connections 变量来使 mysqld 服务进程,对一个指定帐户限定连接数;
18.grant 语句也支持资源控制选项;
19.启动 mysqld 服务进程的安全选项开关, –local-infile=0 或 1, 若是 0 则客户端程序就无法使用 local load data 了,赋权的一个例子 grant insert(user) on mysql.user to ‘user_name’ @'host_name’ ;若使用–skip-granttables 系统将对任何用户的访问不做任何访问控制,但可以用 mysqladmin flush-privileges 或 mysqladmin reload 来开启访问控制;默认情况是 show databases 语句对所有用户开放,可以用–skip-show-databases 来关闭掉。
23.碰到 error 1045(28000) access denied for user ‘root’ @'localhost’ (using password:no)错误时,你需要重 新 设 置 密 码 , 具 体 方 法 是 : 先 用 – skip-grant-tables 参 数 启 动 mysqld , 然 后 执 行 mysql -u root mysql,mysql>update user set password=password(’ newpassword’ ) where user=’ root’ ;mysql>flush privileges;,最后重新启动 mysql 就可以了。
二、 Oracle
1. 什么是存储过程,使用存储过程的好处?(2017-11-25-wzz)
存储过程(Stored Procedure )是一组为了完成特定功能的 SQL 语句集,经编译后存储在数据库中。用户
通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对
象,任何一个设计良好的数据库应用程序都应该用到存储过程。
优点:
(1)允许模块化程序设计,就是说只需要创建一次过程,以后在程序中就可以调用该过程任意次。
(2)允许更快执行,如果某操作需要执行大量 SQL 语句或重复执行,存储过程比 SQL 语句执行的要快。
(3)减少网络流量,例如一个需要数百行的 SQL 代码的操作有一条执行语句完成,不需要在网络中发送数百行代码。
(4) 更好的安全机制,对于没有权限执行存储过程的用户,也可授权他们执行存储过程。
存储过程的具体使用详见:
2. Oracle 存储过程怎么创建?(2017-11-25-wzz)
存储过程创建语法:
create or replace procedure 存储过程名(param1 in type, param2 out type)
as
变量 1 类型(值范围) ;
变量 2 类型(值范围) ;
Begin
Select count(*) into 变量 1 from 表 A where 列名=param1;
If (判断条件) then
Select 列名 into 变量 2 from 表 A where 列名=param1;
Dbms_output。 Put_line(‘打印信息’ );
Elsif (判断条件) then
Dbms_output。 Put_line(‘打印信息’ );
Else
Raise 异常名(NO_DATA_FOUND) ;
End if;
Exception
When others then
Rollback;
End;
注意事项:
1. 存储过程参数不带取值范围, in 表示传入, out 表示输出
2. 变量带取值范围,后面接分号
3. 在判断语句前最好先用 count(*)函数判断是否存在该条操作记录
4. 用 select 。。。 into。。。给变量赋值
5. 在代码中抛异常用 raise+异常名
3. 如何使用 Oracle 的游标?(2017-11-25-wzz)
参考博客:
(1)、 Oracle 中的游标分为显示游标和隐式游标
(2)、显示游标是用 cursor...is 命令定义的游标,它可以对查询语句(select)返回的多条记录进行处理;
(3)、隐式游标是在执行插入 (insert)、删除(delete)、修改(update) 和返回单条记录的查询(select)语句时
由 PL/SQL 自动定义的。
(4)、显式游标的操作:打开游标、操作游标、关闭游标; PL/SQL 隐式地打开 SQL 游标,并在它内部处理 SQL
语句,然后关闭它。
4. Oracle 中字符串用什么连接?(2017-11-25-wzz)
Oracle 中使用 || 这个符号连接字符串 如 ‘abc’ || ‘d’ 的结果是 abcd。
5. Oracle 中是如何进行分页查询的?(2017-11-25-wzz)
Oracle 中使用 rownum 来进行分页, 这个是效率最好的分页方法, hibernate 也是使用 rownum 来进行 Oralce分页的
select * from
( select rownum r,a from tabName where rownum <= 20 )
where r > 10
6. 存储过程和存储函数的特点和区别?(2017-11-25-wzz)
特点:
(1) 、一般来说,存储过程实现的功能要复杂一点,而函数的实现的功能针对性比较强。
(2) 、对于存储过程来说可以返回参数,而函数只能返回值或者表对象。
(3) 、存储过程一般是作为一个独立的部分来执行,而函数可以作为查询语句的一个部分来调用,由于函数可以返回一个表对象,因此它可以在查询语句中位于 FROM 关键字的后面。
区别:
(1)、函数必须有返回值,而过程没有.
(2)、函数可以单独执行.而过程必须通过 execute 执行.
(3)、函数可以嵌入到 SQL 语句中执行.而过程不行.
其实我们可以将比较复杂的查询写成函数.然后到存储过程中去调用这些函数.
7. 存储过程与 SQL 的对比? (2017-11-21-gxb)
优势:
1、提高性能
SQL 语句在创建过程时进行分析和编译。 存储过程是预编译的,在首次运行一个存储过程时,查询优化器对其进行分析、优化,并给出最终被存在系统表中的存储计划,这样,在执行过程时便可节省此开销。
2、降低网络开销
存储过程调用时只需用提供存储过程名和必要的参数信息,从而可降低网络的流量。
3、便于进行代码移植
数据库专业人员可以随时对存储过程进行修改,但对应用程序源代码却毫无影响,从而极大的提高了程序的可移植性。
4、更强的安全性
1)系统管理员可以对执行的某一个存储过程进行权限限制,避免非授权用户对数据的访问
2)在通过网络调用过程时,只有对执行过程的调用是可见的。 因此,恶意用户无法看到表和数据库对象名称、嵌入自己的 Transact-SQL 语句或搜索关键数据。
3)使用过程参数有助于避免 SQL 注入攻击。 因为参数输入被视作文字值而非可执行代码,所以,攻击者将命令插入过程内的 Transact-SQL 语句并损害安全性将更为困难。
4)可以对过程进行加密,这有助于对源代码进行模糊处理。
劣势:
1、存储过程需要专门的数据库开发人员进行维护,但实际情况是,往往由程序开发员人员兼职
2、设计逻辑变更,修改存储过程没有 SQL 灵活
8. 你觉得存储过程和 SQL 语句该使用哪个? (2017-11-21-gxb)
1、在一些高效率或者规范性要求比较高的项目,建议采用存储过程
2、对于一般项目建议采用参数化命令方式,是存储过程与 SQL 语句一种折中的方式
3、对于一些算法要求比较高,涉及多条数据逻辑,建议采用存储过程
9. 触发器的作用有哪些? (2017-11-21-gxb)
1)触发器可通过数据库中的相关表实现级联更改;通过级联引用完整性约束可以更有效地执行这些更改。
2)触发器可以强制比用 CHECK 约束定义的约束更为复杂的约束。与 CHECK 约束不同,触发器可以引用其它
表中的列。例如,触发器可以使用另一个表中的 SELECT 比较插入或更新的数据,以及执行其它操作,如修改数据或显示用户定义错误信息。
3)触发器还可以强制执行业务规则
4)触发器也可以评估数据修改前后的表状态,并根据其差异采取对策。
参考资料:
10. 在千万级的数据库查询中,如何提高效率?(2017-11-23-gxb)
1)数据库设计方面
a. 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
b. 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from t where num is null 可以在 num 上设置默认值 0,确保表中 num 列没有 null 值,然后这样查询: select id from t where num=0
c. 并不是所有索引对查询都有效, SQL 是根据表中数据来进行查询优化的,当索引列有大量数据重复时,查询可能不会去利用索引,如一表中有字段 sex, male、 female 几乎各一半,那么即使在 sex 上建了索引也对查询效率起不了作用。
d. 索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过 6 个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。
e. 应尽可能的避免更新索引数据列,因为索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新索引数据列,那么需要考虑是否应将该索引建为索引。
f. 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
g. 尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
h. 尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。
i. 避免频繁创建和删除临时表,以减少系统表资源的消耗。
j. 临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。
k. 在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先 create table,然后 insert。
l. 如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。
2)SQL 语句方面
a. 应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
b. 应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or num=20 可以这样查询: select id from t where num=10 union all
select id from t where num=20
c. in 和 not in 也要慎用,否则会导致全表扫描,如: select id from t where num in(1,2,3) 对于连续的
数值,能用 between 就不要用 in 了: select id from t where num between 1 and 3
d. 下面的查询也将导致全表扫描: select id from t where name like ‘%abc%’
e. 如果在 where 子句中使用参数,也会导致全表扫描。因为 SQL 只有在运行时才会解析局部变量,但优化
程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的
值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描: select id from t where
num=@num 可以改为强制查询使用索引: select id from t with(index(索引名)) where num=@num
f. 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where num/2=100 应改为: select id from t where num=100*2
g. 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如: select
id from t where substring(name,1,3)= ‘abc ’ – name 以 abc 开 头 的 id select id from t where
datediff(day,createdate,’ 2005-11-30′)=0–‘2005-11-30’生成的 id 应改为: select id from t where name
like ‘abc%’ select id from t where createdate>=’ 2005-11-30′ and createdate<’ 2005-12-1′
h. 不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用
索引。
i. 不要写一些没有意义的查询,如需要生成一个空表结构: select col1,col2 into #t from t where 1=0 这
类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样: create table #t(…)
j. 很多时候用 exists 代替 in 是一个好的选择: select num from a where num in(select num from b)
用下面的语句替换: select num from a where exists(select 1 from b where num=a.num)
k. 任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。
l. 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过 1 万行,那么就应该考虑改写。
m. 尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。
n. 尽量避免大事务操作,提高系统并发能力。
3)java 方面:重点内容
a.尽可能的少造对象。
b.合理摆正系统设计的位置。大量数据操作,和少量数据操作一定是分开的。大量的数据操作,肯定不是 ORM
框架搞定的。,
c.使用 jDBC 链接数据库操作数据
d.控制好内存,让数据流起来,而不是全部读到内存再处理,而是边读取边处理;
e.合理利用内存,有的数据要缓存