十一.增加数据
现有一张student表,表设计如下:
sno为主键并自增,saddress 表示地址,设定了默认值:'广东省广州市'
1.完整的增加一条 insert into tables values(val1,val2,...,valn)
insert into student values(NULL,'李冰','男','libing@qq.com')
注意:
a.必需要保证values() 中的值 与 表中列的按顺序顺序一一对应 ,个数一致
b.sno主键设置自增后,可以交由mysql 自动处理, 可以传入NULL值,此时该记录的 sno 会由自动生成
缺点:当表结构发生变化时,此时insert 会报错
2.按照指定列增加 insert into table_name(column1,column2,...,columnn) values(val1,val2,...,valn)
insert into student(sname,ssex) values('王明','男')
注意:
a.同样需要保证values中的值的个数 与前面指定的 列的个数顺序 对应
优点:
a.列的顺序可以自己指定, 同样value值也要与列名对应 ,以后表中新增列时,insert 语句 不会受影响
b.相比插入完整的一行 , 插入指定列,一些不必要的值,可以不用传, 只需要传一些必传的值,sql语句变的更简洁了
3.增加多行记录 Insert into table_name valuesvalues(val1,val2,...,valn),values(val1,val2,...,valn),values(val1,val2,...,valn)
insert into student values(NULL,'李玲','女','liling163.com'),(NULL,'大才','男',NULL),(NULL,'逍遥','男','xiaoyao@qq.com')
在 1 ,2 的基础上 只需要在values 后 跟上多组数据即可,插入多行
优点: 插入多行有两种形式, 单行插入执行多次 , 多行插入执行1次 , 相比前者而言 ,多行插入执行1次, 性能耗时会大大减少
4.插入 select语句查询出的数据
insert into student(sname,ssex,semail,saddress)
select sname,ssex,semail,saddress from student
这种方式 不会要求select查出的列名与 需要插入数据的表的列名 一致, 只需保证顺序一致, 数据兼容即可
insert 提高数据库性能:
1.生产中, 可能会出现并发访问数据库,进行增删改查的情况, 一般情况查的优先级更高一些. 同时insert 时,需要建立索引 耗时较久,同时还可能造成后续select语句性能的降低
此时可以通过降低 insert 语句的优先级, 来提高性能 ;语法格式: insert low_priority into ... . 同样也适用于delete update语句
2.多行插入执行1次 性能要高于 一行插入执行多次
安全: 可以禁用用户的insert权限,限制部分用户的不可以进行insert 保证数据的安全
十二.更新,删除 数据
update 语句一定要搭配where子句使用,否则更新就是更新整张表中的所有数据,这种误操作,会造成难以想象的结果....
错误: update table_name set column = newValue #会更新表中所有记录该列的值
更新单列 update tablename set column = newValue where condition
update student set semail = 'wangming@qq.com' where sname = '王明'
更新多列update tablename set column1 = newValue1 ,column2 = newValue2,...column_n = newValuen where condition
update student set semail = 'wangming@qq.com',saddress = '广东省东莞市' where sname = '王明'
如果希望在更新某一列或多列出现错误时,不停止update,而是跳过出错的这一列,保持其他列的更新,则可以使用 ignore关键字,格式如下:
update ignore tablename set .....
例子:
不加ignore关键字:
update student set ssex = '未知性别' ,semail = 'wangming@163.com',saddress = '广东省深圳市' where sname = '王明'
执行报错:[Err] 1406 - Data too long for column 'ssex' at row 2
加上ignore关键字:
update IGNORE student set ssex = '未知性别' ,semail = 'wangming@163.com',saddress = '广东省深圳市' where sname = '王明'
如上图所示, 跳过出错处.继续执行
如果希望删除满足条件的行中某一列的值,则直接将 set column = NULL ,即可实现
delete 语句 可以删除 1行 或 多行
同update语句一样,一定要配合where子句使用,否则将会删除整张表中所有的记录
错误:delete from tablename #删除表中所有记录
正确:delete from tablename where .... #删除表中所有符合条件的记录
例子:删除学生表中所有email为空的记录
delete from student where semail = NULL
结果
由于 update , delete没有撤销动作,因此 生产上 如果不加上where 会很危险,未防止误操作,可以取消部分账户的权限访问
如果真的希望清空整张表, 删除所有记录可以使用 truncate table_name 进行代替,
truncate 语句 清空的本质是直接删除原来的表,再重新创建一个同结构的空表. 相对 delete from table_name(逐行删除数) 更快,更高效
十三. 创建表 操作表
13.1.创建表的方式
a:使用可视化工具 ,例如 navicat
b:使用mysql语句
使用mysql 创建表的语法格式
使用括号引起各个列,类似于 java中创建1个表对象 时,初始化各个字段
create table new_table_name (cloumn1 value_type feature, cloumn2 value_type ,feature ... PRIMARY KEY (cloumn)) ENGINE = 存储引擎
mysql语句有一个特点, 会忽略空格, 因此一条语句可以写成一个长行 也可以分成很多行,对于书写新建一个表的操作sql语句,最好是进行换行,更加直观,美观
CREATE TABLE student(
sno int NOT NULL AUTO_INCREMENT,
sname char(50) NOT NULL,
ssex char(2) NOT NULL,
semail char(50) NULL,
saddress char(50) NULL,
PRIMARY KEY (sno)
)ENGINE = InnoDB
其中
NULL 表示允许该列为空值
NOT NULL 表示不允许该列为空值
AUTO_INCREMENT 表示本列值可以自动自增
PRIMARY KEY() 表示主键为哪一列
ENGINE 设置表的存储引擎为 (一般是 InnoDB 和 MyISAM)
注意:
1.如果相同表名 已经在该数据库中存在,此时会报错,而不是覆盖旧的表(这么设计也是为了保证旧表中的数据安全)
2.NULL值不等于 空串 NULL就是没有值的意思
3.PRIMARY KEY 应当保证每个表中都设置主键, 如果使用单列作为主键,则必需保证改列值唯一, 如果使用多列做主键 , 则必需保证多列的组合值唯一,大多数情况都是使用单列作为主键
CREATE TABLE student(
...
PRIMARY KEY (sno,sname)#sno 与 sname 设置为主键
...
)
除此之外 , 主键列,其值不能为NULL ,如果某一列可以允许值为NULL ,则不能作为主键
4.AUTO_INCREMENT 自动递增
在区别学生是否唯一时,设置sno 为主键并且自增 ,因为业务仅仅需要一个不重复且唯一的值即可, 在这个表中 我并关心主键具体的值时多少,因此可以交由mysql自动生成即可!
每个表中只允许有一列设置为 自增,并且他必需被索引(例如,设置为主键)
5.DEFAULT 给定默认值, 如果在插入数据时,没有指定该列的值是多少 ,则新增的这一条件记录 的该列的值 就会设定的默认值
例如,希望新增的值默认性别为男,默认地址为广东省广州市,如果新增时传入,则使用传入的值 设定默认值语法如下:
CREATE TABLE student(
...
ssex char(2) NOT NULL DEFAULT '男',
saddress char(50) NULL DEFAULT '广东省广州市',
...
)
insert into student(sname) values('王明')
默认值 只支持常量值, 不支持 函数
6.ENGINE 引擎类型
创建新表时,如果不加上 ENGINE = value 这个语句, 则表的默认存储引擎是 InnoDB
常用的存储引擎有:
InnoDB: 支持可靠的事务,支持外键,mysql 5.6版本后 支持全文检索, 如果需要事务,则应当选择InnoDB(数据存储在磁盘中)
MyISAM:性能非常高的一种引擎. 支持全文检索,但是不支持事务 (数据存储在磁盘中)
MEMORY:功能等同于MyISAM 但由于数据存储在内存中, 速度要更快 .特别适用于临时表
存储引擎选择:
SHOW ENGINES 查看mysql 支持的所有存储引擎
注意:外键不能跨存储引擎 ,假如:当前表的存储引擎是InnoDB ,需要设置的外键所在表存储引擎为 MyISAM ,则不允许
13.2 修改表
ALTER TABLE table_name operation
1.新增一列 ALTER TABLE 表名 add 列名 列的类型
ALTER TABLE student add test_column char(10)
2.删除一列 ALTER TABLE 表名 drop column 列名
ALTER TABLE student drop column test_column
3.新增外键 新增
新增成绩表 关联学生表
CREATE TABLE score(
d_id int(10) NOT NULL AUTO_INCREMENT,
s_id int(10) NOT NULL ,
dgree decimal(10) NOT NULL,
PRIMARY KEY (d_id)
)
4.建立外键:
ALTER TABLE score
ADD CONSTRAINT fk_score_student FOREIGN KEY(s_id)
REFERENCES student(sno)
ALTER TABLE 之前,应对现有的表做备份后,再进行操作,如果删除了不该删除的列,可以做一定的弥补
13.3 删除表
DROP TABLE score #永久删除 score表
如果删除的表的某一列 被 其他表 设置为外键 ,则必需要删除关联表之后,才能删除该表
报错提示:[Err] 1217 - Cannot delete or update a parent row: a foreign key constraint fails
13.4 重命名表
RENAME TABLE table_name TO new_table_name
例如:修改score表的名称 :
RENAME TABLE score TO my_score
十四.视图
使用数据仍然是 SQL必知必会 中提供的数据
视图不是真正存在的表, 视图相当于把 SELECT 语句 查询出的结果集 存储起来,便于多次使用
14.1 为什么用视图?
1.重用SQL
2.简化复杂的SQL
3.使用表的组成部分,而不是整张表
4.保护数据,修改视图中的内容不会影响原始表中的数据
5.更改数据格式, 视图可以返回与原始表 格式不同的数据
每使用一次视图,就相当于执行一次查询,当创建了复杂的视图 或者视图嵌套较多时,会降低执行的效率
14.2 视图的规则 与 限制
1.视图名称必需唯一, 不能与别的表 和 视图同名
2.视图数量无限制
3.创建视图需要足够的权限
4.视图可进行嵌套
5.视图不能索引,也不能有关联的触发器或默认值
6.视图可以和表一起联结使用
7.ORDER BY 可以用在视图中, 单如果从该视图检索数据SELECT 中 也包含有ORDER BY , 那么该视图中的 ORDER BY 将被覆盖
14.3 创建视图
语法:
方式1:CREATE VIEW view_name AS SELECT ...
方式2:CREATE OR REPLACE VIEW AS SELECT ...如果视图不存在则创建 ,如果存在则替换
14.4 删除视图
DROP VIEW view_name
14.5 查找视图 & 视图的常用之处
使用select 检索 视图内容 与 检索表的用法完全一致
#14.5.1.利用视图简单化复杂的SQL联结
#例:查找产品id 为 TNT2的客户
select * from product_customers_view where prod_id = 'TNT2'
#14.5.2.利用视图重新格式化检索出的数据
#例如将供应商表中的供应商名称与国家 组合成一列进行显示
CREATE VIEW vend_titles AS
SELECT CONCAT(vend_name,'(',vend_country,')') AS vend_title FROM vendors
#14.5.3.利用视图过滤掉不想要的数据
#列出email地址不为空的所有的顾客信息
CREATE VIEW customer_email_list AS
select * from customers where cust_email IS NOT NULL
#在对包含where 子句的视图, 再次使用where子句时, mysql会将两次where子句自动整合
#14.5.4.视图中使用计算字段
#将每个订单的数量 , 单价 与总价显示出
CREATE VIEW orderitem_expend AS
select order_num,
quantity,
item_price,
quantity * item_price as total_price
from orderitems
14.6 视图中的内容是否可更新?
并不是所有的视图都支持更新, 当视图中包含: 分组 , 联结 ,子查询, 聚集函数 ,DISTINCT ,计算列时 ,不可以更新
也就意味着 ,只有简单的SQL单表查询语句构建出的视图,才可以使用更新; 但是正常情况下,构建视图的SQL语句,一般都不会是这种SQL语句
所以基本上视图 是不支持更新的 ,视图的主要功能是用来检索,而不是用于更新
十五.存储过程
简单理解存储过程: 它是为了以后的使用而保存的一条或者多条MySQL的语句集合,可以将其视为批文件,虽然他们的作用不仅仅是批处理;
15.1 创建简单的存储过程
一般逻辑写在 BEGIN 与 END 之间
CREATE PROCEDURE product_avg_price()
BEGIN
SELECT AVG(prod_price) as avg_price FROM products;
END;
15.2 存储过程的调用
调用时需在存储过程的名称后 加上(), 类似于java中调用方法一样
call product_avg_price()
15.3 创建带参数的存储过程
#OUT param 表示由存储过程向外传出1个值 , IN 表示传入存储过程的值 ,INOUT 表示对存储过程传入和传出
#product_price(p1,p2,p3)表示存储过程接收三个参数 ,同时必须指定参数是IN 还是 OUT 以及参数类型
#INTO param 将值保存在指定变量param中 ,一般语法为 SELECT ... INTO param
#根据订单号 检索订单总价
CREATE PROCEDURE getTotalPriceByOrderNum(
IN orderNum INT,
OUT total_price DECIMAL(8,2)
)
BEGIN
SELECT SUM( quantity * item_price)
FROM orderitems
WHERE order_num = orderNum
INTO total_price;
END;
#调用该存储过程,传递的参数必须以@开头 ,
call getTotalPriceByOrderNum(20005,@total_price);
执行后的值将存储在@total_price中, 直接从 SELECT 变量 即可获取
SELECT @total_price
15.4 删除存储过程
DROP PROCEDURE getTotalPriceByOrderNum
15.5 查看存储过程的创建语句 与 状态信息
#查看存储过程的创建语句
SHOW CREATE PROCEDURE product_avg_price
#查看所有已创建的存储过程的状态信息
SHOW PROCEDURE STATUS
15.6 书写稍复杂的存储过程
需求:根据订单号,获取订单号的总金额,并根据传递的标志,判断是否包含税额,如包含,需返回税额与订单总金额
CREATE PROCEDURE getTotalPriceAndTaxByOrderNum(
IN orderNum INT,
IN flag INT,
OUT total_price DECIMAL(8,2)
)
BEGIN
DECLARE total DECIMAL(8,2);
-- 默认税率为6%
DECLARE taxRate INT DEFAULT 6;
-- 求出不包含税额的订单总金额
SELECT SUM( quantity * item_price)
FROM orderitems
WHERE order_num = orderNum
INTO total;
-- 如果包含税额,则将总金额 += 税额
-- flag 非0 即 TRUE
IF flag THEN
SELECT total+(total*taxRate/100) INTO total;
END IF;
-- 最终将总金额赋值给参数total_price,并返回
SELECT total INTO total_price;
END;
#调用该存储过程
#含税
call getTotalPriceAndTaxByOrderNum(20005,0,@total);
SELECT @total;
#不含税
call getTotalPriceAndTaxByOrderNum(20005,1,@total);
SELECT @total;
十六. 游标
游标:是一个存储在MySQL服务器上的数据库查询,它不是一条SELECT 语句,而是被该语句检索出来的结果集.通过游标的移动,可以切换结果集
16.1 创建游标的语法
#创建游标
DECLARE cursor_name CURSOR FOR ... CREATE PROCEDURE processorders() BEGIN DECLARE ordernumbers CURSOR FOR SELECT order_nums FROM orders; END;
16.2 打开与关闭游标的语法
CREATE PROCEDURE processorders() BEGIN DECLARE ordernumbers CURSOR FOR SELECT order_nums FROM orders; #打开游标 OPEN ordernumbers; #关闭游标(此时释放游标所占用的内存资源,在使用完游标后,应当关闭游标,如果没有手动关闭游标,那么MySQL会在到达END语句后自动关闭游标) CLOSE ordernumbers; END;
上述例子仅仅是演示如何创建游标,使用 与 关闭游标. 并没有做额外的操作
16.3 使用游标数据,将游标中的数据 插入到新创建的表中
#创建存储过程 CREATE PROCEDURE processorders() BEGIN #创建Boolean标识 DECLARE done BOOLEAN DEFAULT 0; #创建 tempValue 用于接收游标中的值 DECLARE tempValue INT; #表示订单总额加税后的价格 DECLARE totalPrice DECIMAL(8,2); #创建游标 DECLARE ordernumbers CURSOR FOR SELECT order_num FROM orders; #定义游标的结束--当遍历完成时,将DONE设置为1 DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1; #创建新表 CREATE TABLE IF NOT EXISTS ordertotals( order_num INT NOT NULL, totalPrice DECIMAL(8,2) ); #打开游标 OPEN ordernumbers; #循环取出游标中的数据 REPEAT -- 取出游标中的数据 FETCH ordernumbers INTO tempValue; #根据上一章节定义的存储过程,求出带税价格 CALL getTotalPriceAndTaxByOrderNum(tempValue,1,totalPrice); #将当前数据插入到表ordertotals中 INSERT INTO ordertotals VALUES(tempValue,totalPrice); #当done 为 true时 ,结束循环 UNTIL done END REPEAT; #关闭游标 CLOSE ordernumbers; END; #执行存储过程 CALL processorders();
#执行完毕后即可发现,数据库中新增了一个表
十七. 触发器
触发器,可以理解为 前端中的事件机制,当发生 something时 do someting
MySQL中只有以下语句执行时 可以触发 触发器:
INSERT ,DELETE , UPDATE
17.0 触发器分类
INSERT ,DELETE , UPDATE 的 BEFORE ,AFTER 即前后都可以创建一次触发器,所以每张表最多可创建6个触发器
尽管在MYSQL中只需要保证同一张表的触发器名称唯一,但是在其他DBMS 中触发器的名称在数据库中必须要保持唯一,因此建议触发器名称要保持唯一
17.1 创建触发器
a.创建触发器的四要素:
1.唯一的触发器名称
2.为哪张表新增触发器
3.触发器响应的活动(即INSERT 或 DELETE 或 UPDATE)
4.触发器何时可以执行(在处理之前还是处理之后)
b.创建触发器的语法:
CREATE TRIGGER
#创建触发器 CREATE TRIGGER insert_product AFTER INSERT ON products FOR EACH ROW SELECT NEW.prod_id;
17.2 删除触发器
#删除触发器 DROP TRIGGER insert_product
17.3 使用触发器
#使用INSERT触发器 CREATE TRIGGER insert_order AFTER INSERT ON orders FOR EACH ROW SELECT NEW.order_num; #在INSERT 触发器内部,提供一个可以引用的名为NEW的虚拟表,访问被插入的行 #测试触发器 INSERT INTO orders (order_date,cust_id) VALUES(now(),10001);
#使用DELETE触发器
未完待补充...
十八.事务处理
事务处理:可以用来维护数据库的完整性,它能保证成批的MySQL操作要么完全执行,要么完全不执行
支持事务的存储 : InnoDB
18.1事务存在与否的差别:
当前数据库中有 客户表 customers , 订单表 orders , 订单明细表 orderitems ,通过主键相互关联
当没有事务时流程是:
a.判断数据库中有没有该客户
b.如果有,则检索出客户的ID, 如果没有新增客户 同样可获取到客户ID
c.关联客户ID,新增一行记录到orders 中
d.关联order_num,新增一行记录到orderitems中
正常情况下,该流程没有问题:
假设:
在创建客户后, 新增order记录前 出现了异常,此时客户被新增,订单未被创建; 正常情况下允许,客户没有订单记录 ,这种情况不会造成什么影响
但是在新增order记录后, 新增orderitems之前出现了异常, 此时order记录已经生成, orderitems却没有生成该记录. 一条order记录生成,单没有订单明细,这是非常严重的错误,不应该出现
18.2 有事务支持时流程是:
a.判断数据库中有没有该客户
b.如果有,则检索出客户的ID, 如果没有新增客户 同样可获取到客户ID
c.关联客户ID,新增一行记录到orders 中
d.如果新增orders记录时出现了故障,则回退,整个流程就当从来没有执行过
e.关联order_num,新增一行记录到orderitems中
f.如果新增orderitems记录时出现故障,则回退
g.提交订单信息
18.3 名词介绍:
1.事务(transaction):指一组SQL语句
2.回退(rollback):指撤销SQL语句的过程
3.提交(commit):指将未存储的SQL语句结果写入数据库表中
4.保留点(savepoint):指事务处理过程中设置的临时占位符(placehodler),你可以对他回退,与回退整个事务不同,
类似于打小霸王时,有的游戏支持存档,一旦游戏失败,不会完全从头开始,而是从你的存档处继续
18.4 控制事务
18.4.1 事务的回退/回滚
下面举个简单的例子测试事务的回退/回滚
#第一次查询 存在记录 select * from ordertotals; #开始事务 START TRANSACTION; DELETE FROM order ordertotals #删除后 才是查询ordertotals 表为空 select * from ordertotals; #回滚/回退 事务 ROLLBACK; #最后再次执行检索,发现ordertotals数据恢复了 select * from ordertotals;
哪些语句支持回退?
INSERT , DELETE ,UPDATE ,不支持SELECT语句(这样做并没有意义),不能回退DROP,CREATE操作
18.4.2 事务的commit
一般的SQL语句是直接针对数据库表执行与操作的,这就是所谓的隐含提交(implicit commit),即提交操作是自动进行的
但是在事务处理块中,即事务开启后,所有的操作不会再 隐含提交 ,一切都需要明确的提交 ,即手动提交,此时需要使用 COMMIT语句
commit实例代码如下:
#开启事务 START TRANSACTION; DELETE FROM orderitems where order_num = 20011; DELETE FROM orders where order_num = 20011; #提交事务 COMMIT;
如果在commit之前出了错误, 则事务会自动回退到开启事务时的那个状态,两个删除语句都不会执行
不管是ROLLBACK(回退) 还是 COMMIT (提交) 这两者一旦执行后,事务都会自动关闭
18.4.5 使用保留点
#创建test表
CREATE TABLE test(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
tname VARCHAR(10) NOT NULL
)
#开启事务 START TRANSACTION; INSERT INTO test(tname) VALUES('hello'); #创建一个保留点 SAVEPOINT insert_customer; INSERT INTO test(tname) VALUES('miss'); #回退到指定保留点 ROLLBACK TO insert_customer; INSERT INTO test(tname) VALUES('bye'); #提交事务 COMMIT; SELECT * FROM test
此时结果是 miss 这条记录没有添加进test表中 ,而第一次 与 第三次 都已成功插入;
18.4.6 更改默认提交行为
在非事务中,mysql默认对表的操作的都会自动提交, 可以通过更改autocommit 字段 为 fasle 来关闭自动自动提交,直至自动提交再次开启
#关闭自动提交 SET autocommit = 0; INSERT INTO test(tname) VALUES('cherry'); #此时通过select * 可以读到, 但是未更改autocommit 为真时,表中是不存在该记录的 SELECT * FROM test #开启自动提交 SET autocommit = 1;
十九.全球化 与 本地化
#查看支持的字符集完整列表 SHOW CHARACTER set; #查看所支持校对的完整列表 SHOW COLLATION #查看所有的字符集与校对 SHOW VARIABLES LIKE 'character%'; SHOW VARIABLES LIKE 'collation%'; #创建表时,可以更改默认的字符集与校对 CREATE TABLE test4( id int, tname VARCHAR(10) )DEFAULT CHARSET=utf8 COLLATE utf8_general_ci;
二十.安全管理
在本地测试中,一般使用的账户是root,这个账户拥有所有的权限,但是一般生产上的用户,我们最好单独给他们建立不同的账号,对账号开放不同的权限
例如:某一个用户只需要查找的权限,不希望他能删除,修改表, 那么只需要赋予其查找的权限即可.
又或者需要对某个账号的登录地点做限制 ,只允许该用户在某台主机上访问数据库
为了数据库中数据的安全,建立不同权限的账号是完全有必要的
查看当前数据库创建的所有用户:
#进入mysql数据库 use mysql; #从user表中查询 SELECT * FROM user;
用户权限的相关操作:
#查看某个用户拥有的权限 SHOW GRANTS FOR root #为某个用户增加权限 #为root用户 增加 test数据库下所有表的 SELECT 权限 GRANT SELECT ON test.* TO root
#多个权限之间用逗号隔开
GRANT SELECT,INSERT ON test.* TO root
#移除权限 REVOKE SELECT ON test.* TO root
上述仅举例了SELECT 权限 ,所有可赋予 或者 可撤销权限如下:
二十一.数据库维护
21.1 备份数据
mysql提供了命令可以导入导出数据:
#导出数据前,未保证数据完整,应当刷新当前库中的所有数据
FLUSH TABLES
#导出数据 #1.导出数据库 数据 + 结构 : mysqldump -uroot -p customer > C:UsersTreasureDesktop est.dump #2.导出数据库结构: mysqldump -uroot -p -d customer > C:UsersTreasureDesktop est.dump
21.2 数据库的维护
#分析表 ANALYZE TABLE orders; #检查表 CHECK TABLE orders,productnotes; #如果MyISAM检查结果发现问题, 可以使用REPAIR TABLE 来修复相应的表,这条语句不应该被经常使用,如果经常使用,则可能存在更多的问题 REPAIR TABLE productnotes
二十二.改善性能
仅列举优化的方向:
1.MySQL具有特有的硬件建议(其他DBMS也一样) , 硬件与my.ini配置文件 优化 请参阅:https://www.cnblogs.com/devinzhang/p/8192064.html
2.生产中较为关键的DBMS应该运行在自己专用服务器上
3.MySQL是用一系列默认配置,这些配置开始可能没问题,长时间后可能需要调整内存分配,缓冲区大小,参考 (1) 中的文章
4.MySQL是一个多用户多线程的DBMS,它经常执行多个任务,如果这些任务中的某一个执行缓慢,则所有的请求都会执行缓慢,如果遇到显著的性能不良的请求
则可以使用 SHOW PROCESSLIST 显示所有的活动进程(及他们的线程ID 与 执行时间) 你还可以用KILL 命令终结某个特定的进程(需管理员登录操作)
5.实现同一功能的SQL语句,可能有多种编写方式,尝试联结,子查询 找出性能最优的方案
6.使用EXPLAIN 语句让MySQL解释它将如何执行一条SELECT 语句
7.一般来说 存储过程执行的比一条条执行各个MySQL语句快得多
8.正确的使用列的数据类型也会提高性能
9.绝不要轻易检索比需要多的数据, 例如: 不要轻易使用SELECT * 除非你真的需要这么做
10.有的操作 例如 INSERT 支持一个可选的DELAYED 关键字(延迟调用) ,如果使用它 ,将把控制立即返回给调用程序,并且一旦有可能就实际执行该操作
11.在导入数据时,应该关闭自动提交,你可能还想删除索引, 在导入完成后,重建它们
12.索引是非常有必要的,可以改善数据检索的性能 , 确定索引是一件很微不足道的事情,需要分析使用的SELECT 语句以找出重复的WHERE 与 ORDER BY 子句,如果一个剪得WHERE 子句返回结果
所花时间太长,则可以断定其中使用的列(或几个列)就是需要索引的对象
13.SELECT 语句中 如果存在复杂的OR条件, 可以使用多条SELECT 语句 通过UNION 连接 ,来代替, 可以有显著的性能提升;直观的查看UNION带来的性能提升,请阅:https://blog.csdn.net/bigtree_3721/article/details/72628608
14.LIKE 很慢(需要对数据表中的每一列都进行匹配尝试),一般来说,最好使用FULLTEXT(中文的全文本检索是个问题) 而不是LIKE
15.数据库是不断变化的实体,一组优化良好的表一会可能就面目全非了,由于表的使用和内容的更改,理想的优化和配置也会发生改变.简言之,如果表结构或内容发生了改变,则之前的好的优化方案可能还要跟着变动
16.最重要的规则就是,每条规则在某些特定的条件下都会被打破. 简言之, 应该根据具体情况具体对待
写在结尾:
三篇文章如有描述或sql语句错误,欢迎各位评论中指出,批评
历时1周多终于写完完整的博客,当初的出发点是为了方便自己复习SQL知识,所以排版格式可能有些不成熟 ,不友善.后续的博客会更加注意这方面的问题 后面几个章节可能描述不够细致,如果需要更详细的了解这几张内容,可能需要查阅其他资料
这三篇博客虽然内容大多数参考<< MySQL必知必会>>,但书中有些文字表达可能不够直观,本人对这些地方进行改善,加上自己的话语进行描述,一些代码也是本人亲自书写验证可实施性. 而不是一味的照着书中的内容抄袭;
<< MySQL必知必会>> 我认为是一本非常适合SQL入门的书籍
MySQL 性能优化计划还会额外再写一篇博客, 有这方面需求的可以加个关注.