概述
目录
sql基础
mysql常见数据类型
一、DDL-数据库操作
二、DML-数据操作语言增删改
三 、DQL-数据查询语言,查询数据库中表的记录。查
sql先后执行顺序:
基本查询:
分组查询:
排序查询:
分页查询:
四、DCL-数据控制语言。 管理数据库用户、控制数据库的访问权限
增删改查用户:
权限控制:
sql多表查询
一、内连接
二、外连接
三、自连接
四、联合查询
五、子查询
约束
约束:
联合主键:
二、外键约束:
索引
一、索引结构
建表的同时创建索引:
在已有表上创建索引:
删除索引:
B+Tree索引:
Hash索引:
思考:
二、索引分类
三、索引语法:
四、SQL性能分析
五、索引使用:
①验证索引效率:
②最左前缀法则
查看索引
③范围查询
④索引列运算
⑤字符串不加引号
⑥模糊查询
⑦or连接的条件
⑧数据分布影响
⑨SQL提示
⑩覆盖索引
⑪前缀索引
⑫单列索引与联合索引 选择
六、索引设计原则
七、总结
sql优化
1.insert优化
2.主键优化
3.order by优化
4.group by优化
5.limit优化
6.count优化
7.updata优化
sql基础
mysql常见数据类型
int默认11位,实际可用10位
tinyint unsigned
float(总共位数,小数位数)
char()定长
varchar()变长
set('1','0')集合
year(日期类型数据)取日期中的年
mouth()day()
like模糊搜索 (%0或多个字符,_单个字符)
after 列名添加到哪一列后面
一、DDL-数据库操作
看数据库:
SHOW DATABASES;
创建数据库:
CREATE DATABASE 数据库名;
使用数据库:
USE 数据库名;
查看当前数据库:
SELECT DATABASE();
删除数据库:
DROP DATABASE 数据库名;
DDL-表操作
看表:
SHOW TABLES;
创建表:
CREATE TABLE 表名(字段 字段类型,字段 字段类型);
看表结构:
DESC 表名;
看建表语句:
SHOW CREATE TABLE 表名;
重命名表:
RENAME TABLE 旧表名 to 新表名;
ALTER TABLE 旧表名 RENAME TO 新表名;
删除表:
DROP TABLE 表名;
修改字段名字和类型:
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 类型...;
修改字段类型:
ALTER TABLE 表名 MODIFY 字段名 类型...;
删除字段:
ALTER TABLE 表名 DROP 字段名;
添加字段:
ALTER TABLE 表名 ADD 字段名 类型...;
创建表:
create table emp(
id int comment '编号',
workno varchar(10) comment '工号',
name varchar(10) comment '性名',
gender char(1) comment '性别',
age tinyint unsigned comment '年龄',
idcard char(18) comment '身份证号',
entrydate date comment '入职时间'
)comment '员工表';
修改表:
alter table emp ADD nickname varchar(20) comment '昵称' [约束];
修改字段类型:
ALTER TABLE 表名 MODIFY 字段名 新数据类型(长度);
修改字段名和字段类型:
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 类型(长度) [COMMENT 注释] [约束];
修改表名:
ALTER TABLE 原表名 rename to 新表名;
删除表:
DROP TABLE [IF EXISTS] 表名;
删除指定表,并重新创建该表:
TRUNCATE TABLE 表名;
二、DML-数据操作语言增删改
注意:
①插入数据时,指定的字段顺序需要与值的顺序是一一对应的。
②字符串和日期型数据应包含在引号中。
③插入的数据大小,应在字段的规定范围内。
给指定字段添加数据:
INSERT INTO 表名(字段名1,字段名2,...) VALUES(值1,值2,...);
给全部字段添加数据:
INSERT INTO 表名 VALUES(值1,值2,...);
批量添加数据:
INSERT INTO 表名 (字段名1,字段名2,...) VALUES(值1,值2,...),(值1,值2,...),(值1,值2,...);
INSERT INTO VALUES(值1,值2,...),(值1,值2,...);
修改数据:(没有where则是修改所有)
UPDATE 表名 SET 字段名1=值1,字段名2=值2,... [WHERE 条件];
删除数据:
DELETE FROM 表名 [WHERE 条件];
删表所有数据(一条条删,慢):
delete from 表;
一次清空表:
truncate table 表;
三 、DQL-数据查询语言,查询数据库中表的记录。查
sql先后执行顺序:
SELECT⑤
字段列表
FROM①
表名列表
WHERE②
条件列表
GROUP BY③
分组字段列表
HAVING④
分组后条件列表
ORDER BY⑥
排序字段列表asc升序,desc降序
LIMIT⑦
分页参数
基本查询:
条件查询(WHERE)
聚合函数(count、max、min、avg、sum)
分组查询(GROUP BY)配合聚合查询
排序查询(ORDER BY)
分页查询(LIMIT)
模糊查询 (like)%通配符,一个或多个字符_通配符,一个字符
like binary区分大小写
如果查询内容中包含通配符,可以使用“”转义符。
基本查询:
①查询多个字段
SELECT 字段1,字段2,字段3 ... FROM 表名;
SELECT * FROM 表名;
②设置别名
SELECT 字段1 [AS 别名1],字段2 [as 别名2] ... FROM 表名;
③去除重复记录
SELECT DISTINCT 字段列表 FROM 表名;
分组查询:
SELECT 字段列表 FROM 表名 [WHERE 条件] GROUP BY 分组字段名 [HAVING 分组后过滤条件];
where 与 having 区别:
执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之
后对结果进行过滤。
判断条件不同:where不能对聚合函数进行判断,而having可以。
例子:查询年龄小于45的员工,并根据工作地址分组,获取员工数量大于等于3的工作地址。
select workaddress,count(*) from emp where age<45 group by workaddress having count(*)>=3;
注意:
执行顺序:where>聚合函数>having。
分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义。
排序查询:
SELECT 字段列表 FROM 表名 ORDER BY 字段1 排序方式1,字段2 排序方式2;
排序方式:ASC升序、DESC降序。
分页查询:
SELECT 字段列表 FROM 表名 LIMIT 起始索引,查询记录数;
注意:
①起始索引从0开始,起始索引=(查询页码-1)*每页显示记录数。
②分页查询是数据库的方言,不同数据库有不同的实现,mysql是limit。
③如果查询的是第一页数据,起始索引可以省略,直接简写成 limit10。
四、DCL-数据控制语言。 管理数据库用户、控制数据库的访问权限
增删改查用户:
查询用户:
USE mysql;
SELECT * FROM user;
创建用户:
CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';
修改用户密码:
ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_password BY '新密码';
删除用户:
DROP USER '用户名'@'主机名';
注意:
%通配
权限控制:
ALL, ALL PRIVILEGES所有权限
SELECT查询数据
INSERT插入数据
UPDATE修改数据
DELETE删除数据
ALTER修改表
DROP删除数据库/表/视图
CREATE创建数据库/表
查询权限:
SHOW GREANTS FOR '用户名'@'主机名';
授予权限:
GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'主机名';
撤销权限:
REVOKE 权限列表 ON 数据库名.表名 FROM '用户名'@'主机名';
注意:
①多个权限之间,使用逗号分隔。
②授权时,数据库名和表名可以使用*进行通配,代表所有。
sql多表查询
一、内连接
隐式内连接:
SELCECT 字段列表 FROM 表1,表2 WHERE 条件...
显式内连接:
SELECT 字段列表 FROM 表1 [INNER] JOIN 表2 ON 连接条件...;
二、外连接
左外连接:
SELECT 字段列表 FROM 表1 LEFT [OUTER] JOIN 表2 ON 关联条件 ...[where 条件];
相当于查询 左表的所有数据 包含 表1和表2交集 部分的数据
三、自连接
语法:
SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON 条件 ...;
自连接查询,可以是内连接查询,也可以是外连接查询。
四、联合查询
语法:
SELECT 字段列表 FROM 表A ...
UNION [ALL]
SELECT 字段列表 FROM 表B ...;
①对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致。
②union all 会将全部的数据直接合并在一起, union 会对合并之后的数据去重。
五、子查询
语法:
SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
子查询外部的语句可以是 INSERT / UPDATE / DELETE / SELECT 的任何一个。
根据子查询结果不同,分为:
①标量子查询(子查询结果为单个值)
②列子查询(子查询结果为一列)
常用操作符:IN、NOT IN、ANY、SOME、ALL
③行子查询(子查询结果为一行)
常用操作符:= 、<> 、 IN、NOT IN
④表子查询(子查询结果为多行多列)
常用操作符:IN
根据子查询位置,分为:
①WHERE 之后
②FROM 之后
③SELECT 之后
约束
自增auto_increment只能跟着 唯一 主键 外键 一个表只能有一个
约束:
非空约束NOT NULL
唯一约束UNIQUE可以有一个为空
主键约束PRIMARY KEY非空唯一
默认约束DEFAULT
检查约束CHECK
外键约束FOREIGN KEY保证数据完整性
联合主键:
CREATE TABLE 表名 (
sid int,
course int,
degree float(3,1),
primary key(sid,course)
);
外键删除更新时:
cascade父表改动主键时,检查子表是否有记录,子表对应删除记录
set null父表改动主键时,检查子表是否有记录,有则置空该字段
no action当父表改动时,子表若有记录,不允许更改
restrict当父表改动时,子表若有记录,不允许更改
二、外键约束:
添加外键:
CREATE TABLE 表名(
字段名 数据类型,
...
[CONSTRANT] [外键名称] FOREIGN KEY(外键字段名) REFERENCES 主表(主表列名)
);
修改外键:
ALTER TABLE 表名 ADD CONSTRAINT (外键名称) FOREIGN KEY(外键字段名)
REFERENCES 主表(主表列名);
删除外键:
ALTER TABLE 表名 DROP FOREIGN KEY (外键名称);
ALTER TABLE emp ADD CONSTRAINT fk_emp_dept_id foreign key (dept_id) REFERENCES dept(id);
删除/更新行为:
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段)
REFERENCES 主表名(主表字段)
ON UPDATE CASCADE ON DELETE CASCADE;
索引
一、索引结构
索引是在第三层存储引擎层实现的。
B+Tree索引InnoDB、MyISAM、Memory支持
最常见的索引类型,大部分引擎都支持B+树索引
Hash索引Memory支持
底层数据结构是用哈希表实现的,只有精确匹配索引列的查询才有效,不支持范围查询
R-tree(空间索引)MyISAM支持
空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少
Full-text(全文索引)InnoDB5.6版本后支持、MyISAM支持
是一种通过建立倒排索引,快速匹配文档的方式。类似于Lucene,Solr,ES
建表的同时创建索引:
create table 表名(
字段1 数据类型 [约束条件],
...
[ unique|fulltext ] index [索引名] (字段名[(长度)] [ asc | desc ]
)engine=存储引擎类型;
在已有表上创建索引:
方法一:create [unique|fulltext] index 索引名 on 表名(字段名[(长度)] [asc|desc])
方法二:alter table 表名 add [unique|fulltext] index 索引名 (字段名[(长度)] [asc|desc])
删除索引:
drop index 索引名 on 表名
B+Tree索引:
特点:所有的元素都会在叶子节点中出现。非叶子节点主要起到索引的作用。
叶子节点形成一个单向链表。
MySQL索引数据结构对经典的B+Tree进行了优化。
在原B+Tree的基础上,增加一个指向相邻叶子节点的链表指针,
形成了带有顺序的B+Tree,提高区间访问的性能。
Hash索引:
特点:只能用于对等比较(in,=),不支持范围查询(between,>,<,...)
无法利用索引完成排序操作
查询效率高,通常只需要一次检索就可以了,效率通常要高于B+Tree索引
思考:
为什么InnoDB存储引擎选择使用B+Tree索引结构?
①相对于二叉树红黑树,层级更少,搜索效率高;
②对于B树,无论是叶子节点还是非叶子节点,都会保存数据,这样导致一夜中存储的键值减少,
指针跟着减少,要同样保存大数据量,只能增加树的高度,导致性能降低
③相对Hash索引,B+tree支持范围匹配及排序操作
二、索引分类
主键索引(PRIMARY):针对表中主键创建的索引
默认自动创建,只能有一个
唯一索引(UNIQUE):避免同一个表中某数据列中的值重复、
可以有多个
常规索引:快速定位特定数据
可以有多个
全文索引(FULLTEXT):全文索引查找的是文本中的关键词,而不是比较索引中的值
可以有多个
索引分类(在InnoDB存储引擎中,跟进索引的存储形式,又可以分为以下两种):
聚集索引(Clustered index):必须有,而且只有一个
将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据。
二级索引(Secondary Index):可以存在多个(通过二级索引查询需要回表查询)
将数据与索引分开存储,索引结构的叶子节点关联的是对应的主键。
三、索引语法:
创建索引
(不加 [ UNIQUE | FULLTEXT ] 则为普通索引)
...代表,一个索引关联多个字段,这种称联合索引;一个索引关联一个字段,这种成为单列索引
CREATE [ UNIQUE | FULLTEXT ] INDEX index_name ON table_name (index_col_name,...);
查看索引
SHOW INDEX FROM table_name;
删除索引
DROP INDEX index_name ON table_name;
四、SQL性能分析
SQL执行频率(为sql优化提供支撑)
MYSQL客户端连接成功后,通过 show [session|global] status 命令可以提供服务器状态信息。
通过如下指令,可以查看当前数据库的 INSERT、UPDATE、DELETE、SELECT的访问频次:
SHOW GLOBAL STATUS LIKE 'Com_____';
慢查询日志记录了所以执行时间超过指定参数(long_query_time ,单位:秒,默认10秒)的所有SQL语句的日志。
查看慢查询日志开关状态:(默认关闭)
show variables like 'slow_query_log';
修改慢查询日志参数,需要在MySQL的配置文件(/etc/my.cnf)中配置如下信息:
打开MySQL慢查询日志开关
slow_query_log=1
设置慢日志的时间为2秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志
long_query_time=2
通过以下指令重新启动MySQL服务器进行测试,查看慢日志文件中记录的信息
/var/lib/mysql/localhost-slow.log
SQL性能分析
profile详情
①show profiles 能在做SQL优化时帮助我们了解时间都耗费到哪里去了。
通过have_profiling参数,能看到当前MySQL是否支持profile操作(yes支持,no不支持):
SELECT @@have_profiling;
②默认profiling是关闭的,可以通过set语句在session/global级别开启profiling:
SET profiling=1;1打开0关闭
开启后,可以执行一系列的业务SQL操作,然后通过如下指令查看指令的执行耗时:
①查看每一条SQL的耗时基本情况
show profiles;
②查看指定query_id的SQL语句各个阶段的耗时情况
show profile for query query_id;
③查看指定query_id的SQL语句CPU的使用情况
show profile cpu for query query_id;
五、索引使用:
①验证索引效率:
select * from tb_sku where sn='100010';未创建索引的情况下,SQL耗时长
create index idx_sku_sn on tb_sku(sn);针对字段创建索引后,默认构建B+树索引
select * from tb_sku where sn='100010';已创建索引的情况下,SQL耗时短
②最左前缀法则
如果索引了多列(联合索引),要遵守最左前缀法则。
最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列。
如果跳跃某一列,索引将部分失效(后面的字段索引失效)。
查看索引
show index from tb_user;
③范围查询
联合索引中,出现范围查询(>,<),范围查询右侧的列索引失效。
(规避方法:尽量使用>=或是<=)
④索引列运算
不要在索引列上进行运算操作,索引将失效。
如:explain select * from tb_user where substring(phone,10,2)='15';
⑤字符串不加引号
字符串类型字段使用时,不加引号,索引将失效。
如:explain select * from tb_user where profession='软件工程' and age=31 and status=0;
⑥模糊查询
如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。
如:explain select * from tb_user where profession like '软件%';走索引
explain select * from tb_user where profession like '%软件';不走索引
⑦or连接的条件
用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,
那么涉及的索引都不会被用到。
⑧数据分布影响
如果MySQL评估使用索引比全表更慢,则不使用索引。
⑨SQL提示
SQL提示,是优化数据库的一个重要手段,
简单来说,就是在SQL语句中加入一些人为的提示来达到优化操作的目的。
第一种use index:(告诉数据库,你要用哪个索引)
explain select * from tb_user use index(idx_user_pro) where profession='软件工程';
第二种ignore index:(告诉数据库,不要用哪个索引)
explain select * from tb_user ignore index(idx_user_pro) where profession='软件工程';
第三种force index:(告诉数据库,必须用这个索引)
explain select * from tb_user force index(idx_user_pro) where profession='软件工程';
⑩覆盖索引
尽量使用覆盖索引(查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到),
减少select *。
用explain看执行计划
using index condition:查找使用了索引,但是需要回表查询数据
using where;using index:查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据
⑪前缀索引
当字段类型为字符串(varchar、text等)时,有时候需要索引很长的字符串,
这会让索引变的很大,查询时,浪费大量的磁盘IO,影响查询效率。
此时可以只将字符串的一部分前缀,建立索引,
这样可以大大节约索引空间,从而提高索引效率。
语法:
create index idx_xxxx on table_name(column(n));
前缀长度:
可以根据索引的选择性来决定,而选择性是指不重复的索引值(基数)和数据表的记录总数的比值,
索引的选择性越高则查询效率越高,唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。
select count(distinct email)/count(*) from tb_user;
select count(distinct substring(email,1,5))/count(*) from tb_user;
⑫单列索引与联合索引 选择
单列索引:即一个索引只包含单个列。
联合索引:即一个索引包含了多个列。
在业务场景中,如果存在多个查询条件,考虑针对于查询字段建立索引时,
建议建立联合索引,而非单列索引。
六、索引设计原则
1.针对于数据量较大,且查询比较频繁的表建立索引。
2.针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引。
3.尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
4.如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。
5.尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。
6.要控制索引的数量,索引并不是多多益善,索引越多,维护索引的代价也就越大,会影响增删改的效率。
7.如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。
当优化器知道每列是否包含NULL值时,它可以更好的确定哪个索引最有效地用于查询。
七、总结
1.索引概述
索引是高效获取数据的数据结构;
2.索引结构
B+Tree
Hash(memory引擎的索引结构)只能支持精确匹配,不支持范围查询兼索引排序。
3.索引分类
主键索引、唯一索引、常规索引、全文索引
聚集索引、二级索引(在innodb引擎中根据索引的存储结构来划分的)
聚集索引:在innodb引擎中必须存在,而且只能有一个聚集索引。它最大的特点是,这个
叶子节点下面,挂的是这一行的数据,二级索引叶子节点下面挂的是对应的主键。
聚集索引在一张表中必须存在,默认主键索引就是聚集索引。
如果没有主键,会选择第一个唯一索引作为聚集索引。
没有主键也没有唯一索引,mysql会自动生成一个隐藏的roleid来作为聚集索引。
二级索引:二级索引叶子节点下面挂的是对应的主键。
4.索引语法
create [unique] index xxx索引名 on xxx表名(xxx字段名);创建索引
show index from xxx表名;查看索引
drop index xxx索引名 on xxx表名;删除索引
5.SQL性能分析
执行频次:通过mysql中给我们提供的参数,我们可以看出当前数据库服务器每一种
sql语句执行频次,从而判定当前数据库是更新、插入还是删除为主。在优化sql
时,主要是针对查询来优化。
慢查询日志:通过慢查询日志可以定位出哪些sql语句执行比较耗时,慢查询日志里面只会记录
查询时间超过了预设时间的语句。
profile:可以监控每一条语句的耗时,以及具体的时间耗费在哪个阶段。
explain:查看语句的执行计划来评判sql语句的性能。
6.索引使用
联合索引:必须遵循最左前缀法则
索引失效
SQL提示
覆盖索引
前缀索引
单列/联合索引
7.索引设计原则
哪些表、哪些字段、要建立什么样的索引
sql优化
1.insert优化
①批量插入最多不建议超过1000条
insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'jerry');
②手动事务提交
start transaction;
insert into tb_test_value(1,'Tom'),(2,'Cat'),(3,'jerry');
insert into tb_test_value(4,'Tom'),(5,'Cat'),(6,'jerry');
insert into tb_test_value(7,'Tom'),(8,'Cat'),(9,'jerry');
commit;
③主键顺序插入顺序插入性能高于乱序插入
主键乱序插入:0 1 9 21 88 2 4 15
主键顺序插入:0 1 2 4 9 15 21 88
④大批量插入数据顺序插入性能高于乱序插入
如果一次性需要插入大批量数据,使用insert语句插入性能较低,此时可以使用MySQL数据库
提供的load指令进行插入。操作如下:
#客户端连接服务端时,加上参数 --local-infile
mysql --local-infile -u root -p
#设置全局参数 local_infile 为1,开启从本地加载文件导入数据的开关
set global local_infile = 1;
#执行 load 指令将准备好的数据,加载到表结构中。
#把 /root/sql1.log 文件中的数据,字段按 逗号 分割,行按 换行符 分割,插入到 tb_user 表
load data local infile '/root/sql1.log' into table 'tb_user' fields teminated by ','
lines terminated by 'n';
select @@local_infile;查看 local_infile 参数(sql脚本)
wc -l /root/sql1.log查看 /root/sql1.log 文件行数(linux命令)
2.主键优化
①数据组织方式
在InnoDB存储引擎中,表数据都是根据主键顺序组织存放的,
这种存储方式的表称为索引组织表(index organized table IOT)。
②页分裂(主键乱序插入的情况下,可能会发生页分裂的情况)
页可以为空,也可以填充一半,也可以填充100%。每个页包含了2-N行数据
(如果一行数据过大,会行溢出),根据主键排列。
③页合并
当删除一行记录时,实际上记录并没有被物理删除,只是被标记(flaged)为删除并且它的
空间变得允许被其他记录声明使用。
当页中删除的记录达到 MERGE_THRESHOLD(默认为页的50%),InnoDB 会开始寻找最
靠近的页(前或后)看看是否可以将两个页合并以优化空间使用。
MERGE_THRESHOLD:合并页的阈值,可以自己设置,在创建表或者创建索引时指定。
④主键设计原则
满足业务需求的情况下,尽量降低主键的长度。
插入数据时,尽量选择顺序插入,选择使用AUTO_INCREMENT自增主键。
尽量不要使用 UUID 做主键或是其他自然主键,如身份证号。
(每次生成的UUID是无序的,可能会导致页分裂现象)
业务操作时,尽量避免对主键的修改。
(修改主键还需要去动索引结构,代价比较大
3.order by优化
①Using filesort:通过表的索引或全表扫描,读取满足条件的数据行,然后在排序缓冲区
sort buffer中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫fileSort排序。
②Using index:通过有序索引顺序扫描直接返回有序数据,这种情况即为using index,
不需要额外排序,操作效率高。
#没有创建索引时,根据age,phone进行排序
explain select id,name,phone tb_user order by age,phone;
#创建索引
create index idx_user_age_phone_aa on tb_user(age,phone);
#创建索引后,根据age、phone进行升序排序
explain select id,age,phone from tb_user order by age,phone;
#创建索引后,根据age、phone进行降序排序
explain select id,age,phone from tb_user order by age desc,phone desc;
#根据age,phone进行排序,一个升序,一个降序
explain select id,age,phone from tb_user order by age asc, phone desc;
#创建索引
create index idx_user_age_phone_ad on tb_user(age asc,phone desc);
#根据age,phone进行排序,一个升序,一个降序
explain select id,age,phone from tb_user order by age asc, phone desc;
注意:
根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则。
尽量使用覆盖索引。
多字段排序,一个升序一个降序,此时需要注意联合索引在创建时的规则(ASC/DESC)。
如果不可避免的出现filesort,大数据量排序时,可以适当增大排序缓冲区大小sort_buffer_size(默认256k)。
查看大小sql语句:show variables like 'sort_buffer_size';
4.group by优化
#删除掉目前的联合索引 idx_user_pro_age_sta
drop index idx_user_pro_age_sta on tb_user;
#执行分组操作,根据profession字段分组
explain select profession,count(*) from tb_user group by profession;
#创建索引
create index idx_user_pro_age_sta on tb_user(profession,age,status);
#执行分组操作,根据profession字段分组用的索引
explain select profession,count(*) from tb_user group by profession;
#执行分组操作,根据profession字段分组用的索引(满足最左前缀法则)
explain select age,count(*) from tb_user where profession='软件工程' group by age;
注意:
在分组操作时,可以通过索引来提高效率。
分组操作时,索引的使用也是满足最左前缀法则的。
5.limit优化
对 limit 来说,在大数据量的情况下,越往后,效率越低。
一个常见又非常头疼的问题就是 limit 2000000,10 ,此时需要MySQL排序前2000000记录,
仅仅返回2000000-2000010的记录,其他记录丢弃,查询排序的代价非常大。
优化思路:一般分页查询时,通过创建 覆盖索引 能够比较好的提高性能,可以通过覆盖索引
加子查询的形式进行优化。
explain select * from tb_sku t,(select id from tb_sku order by id limit 2000000,10) a where t.id=a,id;
6.count优化
MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行 count(*) 的时候会直接返回这个数,
效率很高。
InnoDB 引擎就麻烦了,它执行 count(*) 的时候,需要把数据一行一行地从引擎里面读出来,
然后累计计数。
优化思路:自己计数。
count的几种用法:
①count()是一个聚合函数,对于返回的结果集,一行行地判断,如果count函数的参数不是
NULL,累计值就加1,否则不加,最后返回累计值。
用法:count(*)、count(主键)、count(字段)、count(1)
count(主键):
InnoDB 引擎会遍历整张表,把每一行的 主键id 值都取出来,返回给服务层。
服务层拿到主键后,直接按行进行累加(主键不可能为null)。
count(字段):
没有not null约束:InnoDB引擎会遍历整张表把每一行的字段值都取出来,返回给
服务层,服务层判断是否为null,不为null,计数累加。
有not null约束:InnoDB引擎会遍历整张表把每一行的字段值都取出来,返回给服
务层,直接按行进行累加。
count(1):
InnoDB 引擎遍历整张表,但不取值。服务层对于返回的每一行,放一个数"1"进去,
直接按行进行累加。
count(*):
InnoDB 引擎并不会把全部字段取出来,而是专门做了优化,不取值,服务层直接
按行进行累加。
按效率排序,count(字段)<count(主键id)<count(1)约=count(*),所以尽量使用count(*)。
7.updata优化
在更新数据时,一定要根据索引更新,不然就不会是行锁,而升级成表锁,锁住整个表。
InnoDB 的行锁是针对索引加的锁,不是针对记录加的锁,并且该索引不能失效,否则会从
行锁升级为表锁。
最后
以上就是饱满墨镜为你收集整理的一套搞定MySQL基础篇详解+实例+索引、sql索引设计原则、sql性能分析、sql优化sql基础sql多表查询索引sql优化的全部内容,希望文章能够帮你解决一套搞定MySQL基础篇详解+实例+索引、sql索引设计原则、sql性能分析、sql优化sql基础sql多表查询索引sql优化所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复