MYSQL数据库进阶篇

1. 存储引擎

1.1 MySQL体系结构

在这里插入图片描述

1.2 存储引擎

存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式。存储引擎是基于表的,而不是基于库的,所以存储引擎也可被称为表类型。
存储引擎是用来控制数据库如何存,如何取,如何组织的。
不同的存储引擎,索引结构不同。

1.2.1 创建存储引擎

CREATE TABLE 表名 (
	字段1 字段1类型[COMMENT 字段1注释],
	字段2 字段2类型[COMMENT 字段2注释],
	字段3 字段3类型[COMMENT 字段3注释],
	......
	字段6 字段6类型[COMMENT 字段6注释]  # 最后没逗号
) ENFINE = INNODB [COMMENT 表注释];

1.2.2 查看数据库支持的存储引擎

SHOW ENGINES;

1.3 存储引擎特点

1.3.1 InnoDB

  • 介绍:
    InnoDB是一种兼顾高可靠性和高性能的通用存储引擎,在MySQL 5.5之后,InnoDB是默认的MySQL存储引擎。
  • 特点:
    DML操作遵循ACID模型,支持事务
    行级锁,提高并发访问性能;
    支持外键FOREIGN KEY约束,保证数据的完整性和正确性。
  • 文件:
    xxx.ibd: xxx代表的是文件名,innoDB引擎的每张表都会对应一个这样的表空间文件,存储该表的结构(frm、sdi)、数据和索引。
    参数:innodb_file_per_table
    在这里插入图片描述
    这个文件是二进制文件,是看不懂的,想要看懂这个文件,要执行
ibd2sdi table01.ibd

在这里插入图片描述
InnoDB结构特点
在这里插入图片描述

1.3.2 MyISAM

  • 介绍:
    MyISAM是MySQL早期的默认存储引擎。
  • 特点:
    不支持事务,不支持外键。
    支持表锁,不支持行锁。
    访问速度快。
  • 文件
    xxx.sdi: 存储表结构信息
    xxx.MYD: 存储数据
    xxx.MYI: 存储索引
    在这里插入图片描述

1.3.2 MEMORY

介绍:
MEMORY引擎的表数据时存储在内存中的,由于受到硬件问题,或断电问题的影响,只能将这些表作为临时表或缓存使用。
特点:
内存存放
hash索引(默认)
文件:
xxx.sdi: 存储表结构信息。

1.3.3 对比

特点InnoDBMyISAMMEMORY
存储限制64TB
事务安全支持--
锁机制行锁表锁表锁
B+tree索引支持支持支持
Hash索引--支持
全文索引支持(5.6版本后)支持-
空间使用N/A
内存使用中等
批量插入速度
支持外键支持--

1.3.4 存储引擎选择

在选择存储引擎的时候,应该根据应用系统的特点选择合适的存储引擎。对于复杂的应用系统,还可以根据实际情况选择多种存储引擎进行组合。

  • InnoDB:是MySQL的默认存储引擎,支持事务、外键。如果应用对事务的完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入和查询之外,还包含很多的更新、删除操作,那么InnoDB是比较合适的选择。
  • MyISAM:如果应用是以读操作和插入操作为主,只有少量的更新和删除,并且对事务的完整性、并发性要求不是很高,那么选择这个存储引擎是非常适合的。
  • MEMORY: 将所有数据保存在内存中,访问速度快,通常用于临时表及缓存。MEMORY的缺陷就是对表的大小有限制,太大的表无法缓存在内存中,而且无法保障数据的安全性。

1.3.5 总结

  1. 体系结构
    连接层、服务层、引擎层、存储层
  2. 存储引擎特点:
    InnoDB和MyISAM: 事务、外键、行锁
  3. 存储引擎应用
    InnoDB: 存储业务系统对于事务、数据完整性要求较高的核心数据。
    MyISAM: 存储业务系统的非核心业务。

2. 索引

介绍:
索引(index)是帮助MySQL高效获取数据数据库结构有序),在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。
在这里插入图片描述

2.1 索引优缺点

优势劣势
提高数据检索的效率,降低数据库的IO成本索引列也是要占据空间的
通过索引对数据进行排序,降低数据排序的成本,降低CPU的消耗索引大大提高了查询效率,同时也降低了更新表的速度,如对表进行INSERT、UPDATE、DELETE时、效率降低

2.2 索引结构

索引结构描述
B+tree树最常见的索引类型,大部门引擎都支持B+树索引
Hash索引底层数据结构使用哈希表实现的,只有精确匹配索引列的查询才有效,不支持范围查询
R-tree索引(空间索引)空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少
Full-text(全文索引)是一种通过建立倒排索引,快速匹配文档的方式,类似于Lucene,Solr,ES
索引InnoDBMyISAMMEMORY
B+tree索引支持支持支持
Hash索引不支持不支持支持
R-tree索引不支持支持不支持
Full-text5.6版本之后又支持支持不支持

我们平常说的索引,如果没有特殊指明,都是B+树结构组织的索引。

2.3 索引语法

创建索引

CREATE [UNIQUE|FULLTEXT] INDEX 索引名 ON 表名(字段名);

查询索引

SHOW INDEX FROM 表名;

删除索引

DROP INDEX 索引名 ON 表名;

例子:

# 给员工表的name创建索引
CREATE INDEX idx_emp_name ON emp(name);
## 查询员工表的全部索引
SHOW INDEX FROM emp;
# 给员工表的age和salary创建联合索引
CREATE INDEX idx_emp_age_salary ON emp(age, salary);
# 给员工表的name删除索引
DROP INDEX idx_emp_name ON emp;

2.4 SQL性能分析

2.4.1 SQL执行频率

MySQL数据库连接成功后,通过show [global|session] status命令可以提供服务器状态信息,通过如下指令,可以查看当前数据库的INSERT、UPDATE、DELETE、SELECT的访问频率:

SHOW GLOBAL STATUS LIKE 'Com_______';

图片仅为测试数据库
在这里插入图片描述

2.4.2 慢查询日志

慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10s)的所有SQL语句的日志。
MySQL的慢查询日志默认没有开启,需要在MySQL的配置文件(/etc/my.cnf) (linux下)中配置。
windows下可以查找my.cnf文件

mysql --help | findstr /i "my.cnf"
#服务端基本设置
[mysqld]

#开启MySQL慢查询开关
slow_query_log = 1 

#慢日志查询文件路径
slow_query_log_file = D:\dev\mysql-8.1.0-winx64\mysql-8.1.0-winx64\lib/mysql/log-file

# 设置慢查询日志的时间为2s,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志
long_query_time = 2

配置完成之后,通过以下指令重新启动MySQL服务器进行测试,查看日志文件中记录的信息/var/lib/mysql/localhost-slow.log(linux默认位置)。
查询

SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'slow_query_log_file';
SHOW VARIABLES LIKE 'long_query_time';

注意:
linux实用知识
tail 命令可用于查看文件的内容,有一个常用的参数 -f 常用于查阅正在改变的日志文件。
tail -f filename 会把 filename 文件里的最尾部的内容显示在屏幕上,并且不断刷新,只要 filename 更新就可以看到最新的文件内容。

2.4.3 SQL性能分析(profile)

show profiles能够在做SQL优化时帮助我们了解时间都小号到哪里去了。通过have_profileing参数,能否看到当前MySQL是否支持profile操作:

SELECT @@HAVE_PROFILING;

默认profiling是关闭的

profile详情:
执行一系列的业务SQL操作,然后通过如下指令查看指令的执行耗时:

# 查看每一条的SQL的耗时基本情况
SHOW PROFILES;
# 查看指定Query_ID的SQL语句各个阶段的耗时情况
SHOW PROFILE FOR QUERY Query_ID;
# 查看指定Query_ID的SQL语句各CPU的使用情况
SHOW PROFILE CPU FOR QUERY Query_ID;

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.5 SQL性能分析(explain执行计划)

EXPLAIN或者DESC命令获取MySQL如何执行SELECT语句的信息,包括在SELECT语句执行过程中表如何连接和连接的顺序。
语法:

EXPLAIN SELECT 字段列表 FROM 表名 WHERE 条件;

例如:

# 1. 查询研发部和财务部的所有员工信息
EXPLAIN SELECT e.* FROM emp e WHERE e.dept_id IN (SELECT d.id FROM dept d WHERE d.name = '研发部' OR d.name = '财务部');

在这里插入图片描述
explain执行计划各字段含义:

  • id:select查询的序号,标识查询中执行select’子句或者操作表的顺序(id相同,执行顺序从上到下;id不同,值越大,越先执行)。
  • select_type::表示SELECT的类型,常见的取值有SIMPLE(简单表,即不使用表连接或子查询)、PRIMARY(主查询,即外层的查询)、UNION(UNION中的第二个或者后面的查询语句)、SUBQUERY(SELECT/WHERE之后包含了子查询)等。
  • type::表示连接类型,性能由好到差的连接类型为NULL、system、const、eq_ref、ref、range、index、all。
  • possible_key:表示可能应用在这张表上的索引,一个或多个。
  • key:实际使用的索引,如果为NULL,则没有使用索引。

例子:

EXPLAIN SELECT * FROM emp WHERE name = '黎明';

在这里插入图片描述

  • key_len:表示索引中的使用字段,该值为索引最大可能长度,并非实际使用长度,在不损失精确性的前提下,长度越短越好。
  • rows:MySQL认为必须要执行查询的行数,在innodb引擎中,是一个估计值,可能并不是准确的。
  • filtered:表示返回结果的行数占需读取行数的百分比,filtered的值越大越好。

2.6 索引失效情况

2.6.1 最左前缀法则

CREATE INDEX idx_emp_name_age_salary ON emp(name, age, salary);
SHOW INDEX FROM emp;

EXPLAIN SELECT * FROM emp WHERE name = '黎明1' AND age = 66 AND salary = 50000; # key(实际用到的索引)为idx_emp_name_age_salary key_len为92
EXPLAIN SELECT * FROM emp WHERE name = '黎明1' AND age = 66; # key(实际用到的索引)为idx_emp_name_age_salary key_len为87
EXPLAIN SELECT * FROM emp WHERE name = '黎明1'; # key(实际用到的索引)为idx_emp_name_age_salary key_len为82

EXPLAIN SELECT * FROM emp WHERE age = 66 AND salary = 50000;  # key(实际用到的索引)NULL
EXPLAIN SELECT * FROM emp WHERE salary = 50000; # key(实际用到的索引)NULL

EXPLAIN SELECT * FROM emp WHERE name = '黎明1' AND salary = 50000; # key(实际用到的索引)为idx_emp_name_age_salary key_len为82, name后的索引失效,所以为82

如果索引了多列(联合索引),要遵守最左前缀法则。最左前缀法则值得是查询从索引的最左列开始,并且不跳过索引中的列。
如果条约某一列,索引将部分失效(后面的字段索引失效)

2.6.2 范围查询

EXPLAIN SELECT * FROM emp WHERE name = '黎明1' AND age = 66 AND salary = 50000; # key(实际用到的索引)为idx_emp_name_age_salary key_len为92
EXPLAIN SELECT * FROM emp WHERE name = '黎明1' AND age > 66 AND salary = 50000; # key(实际用到的索引)为idx_emp_name_age_salary key_len为87
# age后面的列失效,索引索引长度职位name和age的,没有salary
EXPLAIN SELECT * FROM emp WHERE name = '黎明1' AND age >= 66 AND salary = 50000; # key(实际用到的索引)为idx_emp_name_age_salary key_len为92
# 针对非联合索引

联合索引中,出现范围查询(>,<),范围查询右侧的索引列失效
所以一般为>=, <=

2.6.3 索引列计算

CREATE INDEX idx_emp_name ON emp(name);
DROP INDEX idx_emp_name_age_salary ON emp;
EXPLAIN SELECT * FROM emp WHERE name = 'XXX'; # key(实际用到的索引)为idx_emp_name key_len为82
EXPLAIN SELECT * FROM emp WHERE SUBSTRING(name, 1, 6) = 'XXX'; # key(实际用到的索引)为NULL 针对非联合索引

不要在索引列上进行运算操作,索引将失效

2.6.4 非单

CREATE INDEX idx_emp_name ON emp(name);
EXPLAIN SELECT * FROM emp WHERE name = 'XXX'; # key(实际用到的索引)为idx_emp_name key_len为82
EXPLAIN SELECT * FROM emp WHERE name = 111; # key(实际用到的索引)为NULL 针对非联合索引

字符串不加单引号,造成索引失效

2.6.4 前模糊

CREATE INDEX idx_emp_name ON emp(name);
EXPLAIN SELECT * FROM emp WHERE name LIKE 'XXX%'; # key(实际用到的索引)为idx_emp_name key_len为82
EXPLAIN SELECT * FROM emp WHERE name LIKE '%XXX'; # key(实际用到的索引)为NULL 针对非联合索引

前模糊,索引会失效

2.6.4 or连接的条件

CREATE INDEX idx_emp_name ON emp(name);
SHOW INDEX FROM emp;
EXPLAIN SELECT * FROM emp WHERE name = 'XXX' OR id = 1; # key(实际用到的索引)为idx_emp_name,PRIMARY key_len为82,4
EXPLAIN SELECT * FROM emp WHERE name = 'XXX' OR salary = 50000; # key(实际用到的索引)为NULL OR针对非联合索引

用or分割开的条件,如果or前的条件中的列有索引,而后面的列没有索引,那么涉及到的索引都不会被用到。

2.6.5 数据分布

如果MySQL评估使用索引比全表更慢,则不使用索引。

2.7 SQL提示

SQL提示:是优化数据库的一个重要手段,简单来说,就是在SQL语句中加入一些人为的提示来达到优化操作的目的。

# USE INDEX
EXPLAIN SELECT * FROM emp USE INDEX (idx_emp_name) WHERE name = '黎明1';
# FORCE INDEX
EXPLAIN SELECT * FROM emp FORCE INDEX (idx_emp_name) WHERE name = '黎明1';
# IGNORE INDEX
EXPLAIN SELECT * FROM emp IGNORE INDEX (idx_emp_name) WHERE name = '黎明1';

2.8 覆盖索引

尽量使用覆盖索引(查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到),减少select;

CREATE INDEX idx_emp_name_job_salary ON emp(name, job, salary);
EXPLAIN SELECT name, job, salary FROM emp WHERE name = '黎明1' AND job = 'xxx' AND salary = 50000; # 不需回表
EXPLAIN SELECT name, job, salary, entrydate FROM emp WHERE name = '黎明1' AND job = 'xxx' AND salary = 50000;  #需回

using index condition:查找使用了索引,但是需要回表查询数据
using where; using index; :查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表查询数据。

聚集索引叶子结点挂的是row,非聚集索引挂的是id。
例子:
在这里插入图片描述

一张表,有四个字段(id, username, password, status),由于数据量大,需要对SQL语句进行优化,该如何进行才是最优方案?

CREATE INDEX idx_表_username_password ON(username, password);

建立联合索引。

2.9 索引使用

2.9.1 前缀索引

当字段类型为字符串(varchar、text等)时,有时候需要索引很长的字符串,这会让索引变得很大,查询时,浪费大量的磁盘IO,影响查询的效率。此时可以只将字符串的一部分前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率。

语法:

CREATE INDEX idx_xxx ON table_name(column(n));

索引长度:
可以根据索引的选择性来决定,而选择性是指不重复的索引值(基数)和数据表的记录总数的比值,索引选择性越高则查询效率越高,唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。

SELECT COUNT(DISTINCT email) / COUNT(*) FROM email_test;

SELECT COUNT(DISTINCT SUBSTRING(email, 1, 6)) / COUNT(*) FROM email_test;

例子:

CREATE TABLE email_test(
    id INT PRIMARY KEY AUTO_INCREMENT,
    email VARCHAR(20)
);

INSERT INTO email_test VALUES (1, 'caocao@qq.com'), (2, '1777999@qq.com'), (3, '1777990@qq.com'),(4, 'lisi@qq.com'),(5, 'wangwu@163.com'),(6, '1777999@q163.com'),(7, '657389530@qq.com'),(8, '5353636363@qq.com'),(9, 'gbfbfd@163.com'),(10, '177799559@qq.com');

SELECT COUNT(DISTINCT email) / COUNT(*) FROM email_test;

SELECT COUNT(DISTINCT SUBSTRING(email, 1, 2)) / COUNT(*) FROM email_test;

COUNT(DISTINCT email) / COUNT(*)为1
COUNT(DISTINCT SUBSTRING(email, 1, 2)) 为0.7
COUNT(DISTINCT SUBSTRING(email, 1, 3)) 为0.7
COUNT(DISTINCT SUBSTRING(email, 1, 4)) 为0.7
所以选择前缀索引长度为2

CREATE INDEX idx_email_test_2 ON email_test(email(2));

在这里插入图片描述

2.9.2 单列索引和联合索引

单列索引:即一个索引只包含了一个列。
联合索引: 即一个索引包含了多个列。
在业务场景中,如果存在多个查询条件,考虑针对查询字段建立索引时,建议建立联合索引,而非单列索引。

2.9.3 索引设计原则

  1. 针对数据量较大,且查询比较频繁的表建立索引。
  2. 针对常作为查询条件(where)、排序(order by)、分组(group by)的字段建立索引。
  3. 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
  4. 如果是字符串类型的字段,字段的长度较长,可以针对字段的特点,建立前缀索引。
  5. 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。
  6. 要控制索引的数量,索引并不是多多益善,索引越多,维护索引的代价也就越大,会影响增删改的效率。
  7. 如果索引不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引最有效地应用于查询。

3. SQL优化

3.1 insert插入

  1. 批量插入:
INSERT INTO email_test VALUES (1, 'caocao@qq.com'), (2, '1777999@qq.com'), (3, '1777990@qq.com'),(4, 'lisi@qq.com'),(5, 'wangwu@163.com'),(6, '1777999@q163.com'),(7, '657389530@qq.com'),(8, '5353636363@qq.com'),(9, 'gbfbfd@163.com'),(10, '177799559@qq.com');
  1. 手动提交事务
START TRANSACTION;
INSERT INTO email_test VALUES(11, 'xxx1@qq.com');
INSERT INTO email_test VALUES(12, 'xxx2@qq.com');
INSERT INTO email_test VALUES(13, 'xxx3@qq.com');
COMMIT;
  1. 主键顺序插入

主键乱序插入:8 1 9 21 88 2 6 89 7 10
主键顺序插入:1 2 8 10 28 30 31 60 70 90

大批量插入数据: 如果要一次性插入大批量数据,使用insert语句插入性能较低,此时可以使用MySQL数据库提供的Load指令进行插入。

在这里插入图片描述

# 客户端连接服务器时, 加上参数--local-infile
mysql --local-infile -uroot -p
# 设置全局参数local_infile为1,开启从本地加载文件导入数据的开关
SET GLOBAL LOCAL_INFILE = 1;
# 指令load指令将准备好的数据,加载到表结构中
LOAD DATA LOCAL INFILE 'D:\\aaa.log' INTO TABLE email_test FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';

SELECT @@LOCAL_INFILE;

3.2 主键插入

在这里插入图片描述
主键设计原则:

  1. 满足业务需求的前提下,尽量降低主键的长度。
  2. 插入数据时,尽量选择顺序插入,使用AUTO_INCREMENT自增主键。
  3. 尽量不要使用UUID做主键或者是其他自然主键,比如身份证号。
  4. 业务操作时,避免对主键的修改。

3.3 order by优化

  1. Using filesort:通过表的索引或者全表扫描,读取满足的数据行,然后在排序缓冲区sort buffer中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫FileSort排序。
  2. Using index:通过有序索引顺序扫描直接返回数据,这种情况叫using index,不需要额外排序,操作效率高。
# order by优化
# 没有创建索引时,根据age,job进行排序
EXPLAIN SELECT id, age, job FROM emp ORDER BY age, job; #Using filesort

# 创建索引
CREATE INDEX idx_age_job ON emp(age,job);

# 创建索引后,根据age,job进行升序排序
EXPLAIN SELECT id, age, job FROM emp ORDER BY age, job; #Using index

# 创建索引后,根据age,job进行降序排序
EXPLAIN SELECT id, age, job FROM emp ORDER BY age DESC, job DESC; #Backward index scan; Using index

EXPLAIN SELECT id, age, job FROM emp ORDER BY job, age; #Using index; Using filesort job在age前

EXPLAIN SELECT id, age, job FROM emp ORDER BY age ASC , job DESC; #Using index; Using filesort

优化根据age,job一个升序,一个降序

CREATE INDEX idx_emp_age_job_ad ON emp(age ASC , job DESC);

EXPLAIN SELECT id, age, job FROM emp ORDER BY age ASC , job DESC; #Using index

优化准则:

  1. 根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则。
  2. 尽量使用覆盖索引。
  3. 多字段排序,一个升序一个降序,此时需要注意联合索引在创建时的规则(ASC/DESC)。
  4. 如果不可避免的出现filesort,大数据量排序时,可以适当增加缓冲区大小sort_buffer_size(默认256k)。

3.4 group by优化

# 删除不必要的索引
# 1. 根据age进行分组
EXPLAIN SELECT age, COUNT(*) FROM emp GROUP BY age; #Using temporary
# 2. 创建索引
CREATE INDEX idx_age_job_salary ON emp(age, job, salary);
# 有索引后,根据age进行分组
EXPLAIN SELECT age, COUNT(*) FROM emp GROUP BY age; #Using index
# 有索引后,根据age,job 分组
EXPLAIN SELECT age, job, COUNT(*) FROM emp GROUP BY age, job; #Using index

EXPLAIN SELECT job, COUNT(*) FROM emp GROUP BY job ; # Using index; Using temporary

EXPLAIN SELECT job, COUNT(*) FROM emp WHERE age = 22 GROUP BY job; # Using index
  1. 在分组操作时,可以通过索引来提高效率。
  2. 分组操作时,索引的使用也是满足最左前缀法则。

3.5 limit优化

一个常见又头疼的问题就是limit 2000000, 10,此时需要MySQL排序前2000010条数据,仅仅返回2000000-2000010的记录,其他记录丢弃,查询排序的代价非常大。

SELECT * FROM emp ORDER BY id LIMIT 2000000, 10;
SELECT * FROM emp WHERE id IN (SELECT * FROM emp ORDER BY id LIMIT 2000000, 10); #[42000][1235] This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
# 上面的不行,所以只能使用内连接了
SELECT e1.* FROM emp e1, (SELECT * FROM emp ORDER BY id LIMIT 2000000, 10) e2 WHERE e1.id = e2.id;

优化思路:一般分页查询时,通过创建覆盖索引能够比较地提高性能,可以通过覆盖索引加子查询形式进行优化。

3.6 count优化

EXPLAIN SELECT COUNT(*) FROM emp;

MyISAM:引擎把一个表的总行数存在了磁盘上,因此执行count(*)的时候会直接返回这个数,效率很高。
InnoDB:引擎就麻烦了,它执行count(*)的时候,需要把数据一行一行地从引擎里读出来,然后累积计数。

优化思路:自己计数
count的几种用法:

  1. count(主键)
    InnoDB引擎会遍历整张表,把每一行的主键id值都取出来,返回给服务层。服务层拿到主键后,直接按行进行累加(主键不可能为null)。
  2. count(字段)
    没有not null约束: InnoDB引擎会遍历整张表把每一行的字段值取出来,返回给服务层,服务层判断是否为null,不为null,计数累加。
    有not null约束:InnoDB引擎会遍历整张表把每一行的字段值都取出来,返回给服务层,直接按行进行累加。
  3. count(1)
    InnoDB引擎遍历整张表,但不取值。服务层对于返回的每一行,放一个数字“1”进去,直接按行进行累加。
  4. count(*)
    InnoDB引擎并不会把全部字段取出来,而是专门做了优化,不取值,服务层直接按行进行累加。

按照效率排序的话, count(字段) < count(主键id) < count(1) < count(*)。所以进行使用count(*)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值