数据库,后端开发者必学,而且现在以MySQL居多。这个系列将系统化MySQL一些高级用法。打算先讲很多人关注的使用方式(增删改查以及其优化),然后就讲数据库和表的操作(很多我们学习忽略的地方),接着就是引擎还有更高级的查询等等。OK,不多说,Let’s go!
本系列会逐步更新,从基本知识总结,到sql优化,索引设计优化,存储过程使用优化......并且到后面会给出一些方案设计,比如集群,主从......
敬请期待!!
本人能力有限,有写得不对的,麻烦在下面指出,十分感谢!
(一)操作数据操作语句优化认识;
(二)INSERT语句;
(三)DELETE语句;
(四)UPDATE语句;
(五)REPLACE语句;
(六)库与表基本操作
通常情况下,当访问某张表的时候,读取者首先必须获取该表的锁,如果有写入操作到达,那么写入者一直等待读取者完成操作(查询开始之后就不能中断,因此允许读取者完成操作)。当读取者完成对表的操作的时候,锁就会被解除。如果写入者正在等待的时候,另一个读取操作到达了,该读取操作也会被阻塞(block),因为默认的调度策略是写入者优先于读取者。当第一个读取者完成操作并解放锁后,写入者开始操作,并且直到该写入者完成操作,第二个读取者才开始操作。
通过LOCK TABLES和UNLOCK TABLES语句可以显式地获取或释放锁,但是在通常情况下,服务器的锁管理器会自动地在需要的时候获取锁,在不再需要的时候释放锁。获取的锁的类型依赖于客户端是写入还是读取操作。
对某张表进行写入操作的客户端必须拥有独占的(排他的)访问权的锁。操作在进行的过程中,该数据表处于不一致的(inconsistent)状态,因为数据记录在删除、添加或修改的时候,数据表上的索引也可能需要更新以相互匹配。允许两个客户端同时写入一张数据表是不利的,因为这样的操作会很快使数据表中的信息成为一堆无用的垃圾。同时允许客户端读取变化之中的数据表也不正确,因为正在读取的位置中的数据可能正在变化(修改),读取的结果可能并不是真实的。因此对某张表执行读取操作的客户端也必须获取一个锁,防止在读取的过程中,其它的客户端写入或改变表。但是这个锁不需要独占的访问权。因为读取操作不会改变数据,因此没有理由让某个读取者阻止其它的读取者访问这张表。故读取锁可允许其它的客户端在同一时刻读取这张表。
虽然通过锁机制,可以实现多线程同时对某个表进行操作,但当某个线程作更新操作时,首先要获得独占的访问权。在更新的过程中,所有其它想要访问这个表的线程必须要等到其更新完成为止。此时就会导致锁竞争的问题,从而导致用户等待时间的延长。
CREATE TABLE `score` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`change_type` VARCHAR(255) NULL DEFAULT NULL,
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`score` INT(11) NULL DEFAULT NULL,
`user_id` BIGINT(20) NULL DEFAULT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci';
//外键在以后再聊
CREATE TABLE `gag` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`gag_time` DATE NULL DEFAULT NULL,
`user_id` BIGINT(20) NULL DEFAULT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci';
如果要插入的值列表包含所有字段并且顺序一致,则可以省略字段列表。
可同时插入多条数据记录!
例子:
INSERT INTO score (change_type,score,user_id) VALUES ('吃饭',10,1);
例如说,如果有需要插入100000条数据,那么就需要有100000条insert语句,每一句都需要提交到关系引擎那里去解析,优化,然后才能够到达存储引擎做真的插入工作。上述所说的同时插入多条就是一种优化。(经测试,大概10条同时插入是最高效的)
INSERT INTO score (change_type,score,user_id) VALUES ('吃饭',10,1),('喝茶',10,1),('喝茶',10,1);
没有条件子句,则会删除全部
DELETE FROM gag; 删除全部
DELETE FROM gag WHERE id=1;
truncate table gag;
truncate table 能重新利用释放的硬盘空间,在InnoDB Plugin中,truncate table为自动回收,如果不是用InnoDB Plugin,那么需要使用optimize table来优化表,释放空间。
如果外键指定级联删除(delete cascade),关联的子表也会会被删除所有表数据。如果外键未指定级联(cascde),truncate table逐行删除数据,如果是父行关联子表行数据,将会报错。
一个大的 DELETE 或 INSERT 操作,要非常小心,因为这两个操作是会锁表的,表一锁住,其他操作就进不来了。因此,我们要交给DBA去拆分,重整数据库策略,比如限制处理1000条。
MySQL官方手 册得知删除数据的速度和创建的索引数量是成正比的。所以在超大型数据库中,删除时处理好索引关系非常重要。推荐的折中方法:在删除数据之前删除这那几个索引,然后删除其中无用 数据,删除完成后重新创建索引。
UPDATE score SET change_type='洗澡' WHERE id=2;
Update score
SET change_type = CASE id
WHEN 1 THEN 'value1'
WHEN 2 THEN 'value2'
WHEN 3 THEN 'value3'
END
WHERE id IN (1,2,3)
Update score
SET change_type = CASE id
WHEN 1 THEN 'value1'
WHEN 2 THEN 'value2'
WHEN 3 THEN 'value3'
END ,
score = CASE id
WHEN 1 THEN 1
WHEN 2 THEN 2
WHEN 3 THEN 3
END
WHERE id IN (1,2,3)
例如:如果一个表在一个字段上建立了唯一索引,当向这个表中使用已经存在的键值插入一条记录,将会抛出一个主键冲突的错误。如果我们想用新记录的值来覆盖原来的记录值时,就可以使用REPLACE语句。
使用REPLACE插入记录时,如果记录不重复(或往表里插新记录),REPLACE功能与INSERT一样,如果存在重复记录,REPLACE就使用新记录的值来替换原来的记录值。使用REPLACE的最大好处就是可以将DELETE和INSERT合二为一,形成一个原子操作。这样就可以不必考虑同时使用DELETE和INSERT时添加事务等复杂操作了。
在使用REPLACE时,表中必须有唯一有一个PRIMARY KEY或UNIQUE索引,否则,使用一个REPLACE语句没有意义。
//含义一:与普通INSERT一样功能
REPLACE INTO score (change_type,score,user_id) VALUES ('吃饭',10,1),('喝茶',10,1),('喝茶',10,1);
//含义二:找到第一条记录,用后面的值进行替换
REPLACE INTO score (id,change_type,score,user_id) VALUES (1,'吃饭',10,1)
此语句的作用是向表table中插入3条记录。如果主键id为1或2不存在就相当于插入语句:
INSERTINTO score (change_type,score,user_id) VALUES (‘吃饭’,10,1),(‘喝茶’,10,1),(‘喝茶’,10,1);
如果存在相同的值则不会插入数据。
//用法一:并不是修改数据,而只是单纯做局部替换数据返还而已。
SELECT REPLACE('喝茶','茶','喝')
//结果: 喝喝
UPDATE score SET change_type=REPLACE(change_type,'做任务','bb')
1)UPDATE在没有匹配记录时什么都不做,而REPLACE在有重复记录时更新,在没有重复记录时插入。
2)UPDATE可以选择性地更新记录的一部分字段。而REPLACE在发现有重复记录时就将这条记录彻底删除,再插入新的记录。也就是说,将所有的字段都更新了。
其实REPLACE更像INSERT与DELETE的结合。
show databases;
use table;
select database();
select now(), user(), version();
create database[ if not exists] 数据库名 数据库选项
数据库选项:
CHARACTER SET charset_name
COLLATE collation_name
show create database 数据库名
alter database 库名 选项信息
drop database[ if exists] 数据库名
同时删除该数据库相关的目录及其目录内容
create [temporary] table[ if not exists] [库名.]表名 ( 表的结构定义 )[ 表选项]
每个字段必须有数据类型
最后一个字段后不能有逗号
temporary 临时表,会话结束时表自动消失
对于字段的定义:
字段名 数据类型 [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] [COMMENT 'string']
ALTER TABLE 【表名字】 DROP 【列名称】
ALTER TABLE 【表名字】 ADD 【列名称】 INT NOT NULL COMMENT ‘注释说明’
ALTER TABLE 【表名字】 CHANGE 【列名称】【新列名称(这里可以用和原来列同名即可)】 BIGINT NOT NULL COMMENT ‘注释说明’
ALTER TABLE 【表名字】 CHANGE 【列名称】【新列名称】 BIGINT NOT NULL COMMENT ‘注释说明’
ALTER TABLE 【表名字】 RENAME 【表新名字】
Alter TABLE 【表名字】 drop primary key
ALTER TABLE sj_resource_charges ADD CONSTRAINT PK_SJ_RESOURCE_CHARGES PRIMARY KEY (resid,resfromid)
ALTER TABLE sj_resource_charges add index INDEX_NAME (name);
ALTER TABLE sj_resource_charges add unique emp_name2(cardnumber);
Alter table tablename drop index emp_name;
SHOW TABLES;
SHOW CREATE TABLE 表名 (信息更详细)
DESC 表名 / DESCRIBE 表名 / EXPLAIN 表名 / SHOW COLUMNS FROM 表名 [LIKE 'PATTERN']
SHOW TABLE STATUS [FROM db_name] [LIKE 'pattern']
RENAME TABLE 原表名 TO 新表名
RENAME TABLE 原表名 TO 库名.表名 (可将表移动到另一个数据库)
-- RENAME可以交换两个表名
DROP TABLE[ IF EXISTS] 表名
TRUNCATE [TABLE] 表名
CREATE TABLE 表名 [AS] SELECT * FROM 要复制的表名
现在罗列给大家,这是积累的必经一步,我会继续出这个系列文章,分享经验给大家。欢迎在下面指出错误,共同学习!!你的点赞是对我最好的支持!!