参考:https://www.runoob.com/mysql/mysql-install.html
注意:安装路径千万不要包含中文字符
启动mysql:net start mysql
关闭mysql:net stop mysql
连接数据库:mysql -u root -p
选择要操作的数据库:use
显示所有的数据库:show databases
显示当前数据库的所有表:show tables
显示表的信息:show columns from
创建数据库:create database wordpress
DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 指定字符集)
删除数据:drop
参考:https://www.runoob.com/mysql/mysql-data-types.html
mysql> CREATE TABLE vc (v VARCHAR(4), c CHAR(4));
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO vc VALUES ('ab ', 'ab ');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT CONCAT('(', v, ')'), CONCAT('(', c, ')') FROM vc;
+---------------------+---------------------+
| CONCAT('(', v, ')') | CONCAT('(', c, ')') |
+---------------------+---------------------+
| (ab ) | (ab) |
+---------------------+---------------------+
1 row in set (0.06 sec)
<4>char和varchar的优缺点
char:查询效率高(不需要计算机字段的长度),不会产生内存碎片。可能会浪费存储空间。
varchar:长度可变,查询效率低(需要先取字段的长度),会产生内存碎片(更新一个字段,字段所占字节数减少了),可能会导致页分裂。
https://dev.mysql.com/doc/refman/8.0/en/char.html
(5)null值:
1、NULL只支持IS NULL、IS NOT NULL、IFNULL()操作;
2、NULL对数学比较运算符(>, =, <=, <>)运算出的结果都是FALSE;
3、索引列是允许存在NULL的(所有的null值都对应着索引;
4、DISTINCT、GROUP BY、ORDER BY中认为所有的NULL值都是相等的;
5、ORDER BY认为NULL是最小的值;
6、MIN()、SUM()、COUNT()在运算时会忽略NULL值,但是COUNT(*)不会忽略;
7、TIMESTAMP类型的字段被插入NULL时,实际写入到表中的是当前时间;
8、AUTO_INCREMENT属性的字段被插入NULL时,实际写入到表中的是顺序的下一个自增值;
9、想要禁止某个字段被设置为NULL,则对此字段设置NOT NULL属性;
10、如非必要,不要使用NULL,会带来不可预料的麻烦。
原文链接:https://blog.csdn.net/ljl890705/article/details/97263432
create table
select [distinct] column_name1, column_name2,…,column_namen
from
where condition1 [and,or] condition2 [and,or] …
group by
having
order by column_name1 [asc,desc]
(1)执行顺序:from… where…group by… having… select … order by…
(2)在where中的判断语句中,除了不等号可以用<>或者!=之外其他都与c,c++,java中的相同。在where中查询字符串时不区分大小写,可以通过加入关键字binary来指定查找时区分大小写比如:binary name = ‘Zhang san’。NULL与任何值比较都返回null,需要用is null 或者is not null判断是否非空。使用<=>时,若两者相等或者两者都为NULL则返回true。
(3) like子句实现模糊匹配:%匹配任意字符,也可以使用正则表达式进行匹配。
(4) union,union all, union distinct:
select column_name1, column_name2
from table1
union [distinct,all]
select column_name1,column_name2
from table2
合并两张表的搜索结果,union和union distinct作用相同都会删除重复元素,union all会保留重复结果并且union all效率远高于union。
(5)group by子句
按照某个数学对数据分组,在gruop by column_name1后可加with rollup对所有的数据求和。不指定名字时,这列的名字为NULL,可用coalesce(a,b,c)来指定这列的名字,如果anull则选择b,如果bnull则选择c,如果a!=null则选择a。
(6)inner join, left join, right join
select column_name1,column_name2,…,column_namen
from talbe1 inner join [left join,right join] table2
on xxxx
inner join:两边的列满足具体的条件时才连接,on后关于两个表的筛选条件都会生效
left join:左边的列都会取到,右边没有满足条件的列值为空,on后只有关于右边表的筛选条件会生效
right join:右边的列都会取到,左边没有满足条件的列值为空,on后只有关于左边表的筛选条件会生效
1、小表驱动大表
根据X表中的数据去另Y表中查找数据就是X表驱动Y表,为什么要小表驱动大表呢?类似于for循环,
for i in X
search i in Y
对于内存循环,可以使用到数据库的索引查询速度快,对于外层循环则无法使用到索引,速度慢。
2、in和exsits的区别:in是子查询驱动外层查询,exist是外层查询驱动子查询。
<1>in:子查询为驱动表,外面的表为被驱动表(主要因为in一般是非关联子查询),因此内表小外表大。
select * from X where X.id in (select id from Y);
//等价于
for i = Y.id
search i in X.id
<2>exists:外面的表为驱动表,子查询为被驱动,因此外表大,内标表小。
select * from X where exists (select * from Y where X.id = Y.id);
//等价于
for i in X.id
search i in Y.id
https://www.cnblogs.com/developer_chan/p/9247185.html
https://blog.csdn.net/coollei2008/article/details/100376976?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166377026916782388052126%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=166377026916782388052126&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-1-100376976-null-null.142v49control_1,201v3add_ask&utm_term=in%E5%92%8Cexist%20&spm=1018.2226.3001.4187
插入:insert into
values
(value1,value2,…,valuen);
更新:update
set field1 = value1, field2 = value2,…
where …
删除:delete from
where …
drop table
alter table…
添加列
alter table 表名 add columnname 类型
删除列
alter table 表名 drop columnname
修改列的类型
alter table 表名 modify columnname 类型
修改列的列名
alter table 表名 change columnname 新名字 类型
创建方式:
(1)create [unique] index indexname on tablename(columnname);
(2)alter table tablename add [unique] index indexname(columnname);
(3)create table tablename(
index indexname(columnname)
)
create temporary table …
除了需要添加temporary 关键字以外,其他与正常表一样。当断开与数据库的连接后,临时表会自动被销毁。
<1>查询语句:select
<2>DML数据操纵语句:delete,insert,update
<3>DDL数据定义语句:create,drop,alter
<4>DCL数据控制语句:grant,revoke
<5>TCL事务控制语句:commit,rollback,savepoint
<6>聚合查询:max(),min(),avg()等
<7>关联查询:inner join(取两个表中满足条件的列),left join(左边的都取,右边的取满足条件的列),right join(右边都取,左边取满足条件的列),union (两个表的列的所有排列并且去重),union all(不去重)
<8>语句的执行顺序:
<9>in 和 exists的区别:in会先将子查询结果合并为一个集合,然后判断每一条记录的task_id是不是在这个集合里。exists先取出t1的一条记录,然后执行EXIST如果EXIST返回true(子查询结果不为空时返回true)则包含这条查询结果。
in适合于子查询结果集大而外表小的情况,exist适用于子查询结果集小而外表大的情况。
SELECT SQL_NO_CACHE t1.id FROM tb_data t1 WHERE t1.task_id IN (SELECT t2.id FROM tb_task t2);
SELECT SQL_NO_CACHE t1.id FROM tb_data t1 WHERE EXISTS (SELECT * FROM tb_task t2 WHERE t1.task_id = t2.id);
<10>drop:删除表,truncate:清空表中数据,delete:删除表中满足条件的数据。执行效率drop > truncate > delete
<11>limit:select xxx from xxx limit n:取前n条数据,select xxx from xxx limit start, n:从下标start开始向后取n条数据,第一个元素的下标为0,select xxx from xxx limit start, -1从下标start开始向后取所有数据。
<12>order by: select xxx from xxx order by column1, column2 desc:注意desc只能作用到column2。
<13>时间有关的函数:year(xxx)获取年份,month(xxx)获取月份,date_format(xxx, ‘%Y-%m’)将时间按照指定格式输出
<14>单引号(‘’),双引号(“”),反引号(``)的区别:单引号和双引号都可以表示字符串,单引号、双引号和引号都可表示别名(select * as ‘xxx’),反引号可以表示列名或者表名。
<15>distinct是对查询的所有字段去重所以必须要位于查询字段的最前面,如果和聚合函数使用例如count(distinct xxx)则只作用于这个字段
属性不可再分,比如student属性下有(id,name),这就不满足第一范式
在第一范式的基础上消除了部分函数依赖(有主键,并且所有非主属性必须完全依赖与候选码),比如(姓名,年龄,比赛时间,比赛场地,得分)中主键为(姓名,比赛场地,比赛时间),年龄只依赖于姓名,不满足第二范式。
不满足第二范式的缺点:数据冗余,插入异常,删除异常,修改异常。
在第二范式的基础上消除了传递函数依赖(所有非主属性都依赖于候选码并且非主属性不能依赖于其他非主属性)。比如(球员编号,球队编号,教练),球队编号依赖于球员编号,教练又依赖于球队编号)。
不满足第三范式的缺点:数据冗余,插入异常,删除异常,修改异常
<1>原子性:事务是最小的执行单位,要么全做、要么全不做。
保证:undo log(回滚日志)
<2>一致性:事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态,也就是说事务要保证执行前后数据库中的数据都是正确的,执行前后数据库的完整性都没有遭到破坏。
保证:原子性、隔离性、持久性都是为了保证一致性,undo log + redo log
<3>隔离性:并发情况下,事务与事务的执行不能相互干扰,这是一致性的重要保障。
保证:锁机制和MVCC
<4>持久性:事务提交后对数据库的更改是持久的,即使数据库发生故障也不能影响。
保证:redo log(重做日志),Mysql将更新的数据先写到Buffer Pool缓存中,再定期从缓存刷到磁盘来提高执行效率。为了解决Mysql宕机造成的数据丢失,Mysql先将写操作写入日志文件中,再将更新数据写到Buffer Poll中。
脏读、幻读、不可重复读,丢失更新
<1>读未提交:上面的三个问题都没有解决
<2>读已提交:解决了脏读
<3>可重复读:在读已提交的基础上解决了不可重复读
<4>可串行化:在可重复读的基础上解决了幻读
全局锁、表级锁、行级锁
#加全局锁,这会锁住所有的数据库
mysql> flush tables with read lock;
#释放锁
mysql> unlock tables;
#逻辑备份,注意mysqldump不是mysql语句而是mysql提供的一个命令
[root@localhost ~]# mysqldump -uroot –p1234 itcast > itcast.sql
#加读锁
lock tables stu read;
#解锁
unlock tables;
2、写锁(write lock),添加写锁之后,除了添加锁的用户之外所有的读写操作和添加锁操作都会被阻塞。
#加读锁
lock tables stu write;
#解锁
unlock tables;
<2>元数据锁:
1、元数据可以简单理解为表的结构。表锁锁的是表中的数据,元数据锁锁的是表的结构。引入元数据锁是为了防止DML与DDL语句冲突,比执行select,insert,update,delete的过程中,如果表的结构发生了改变将导致严重的错误。元数据锁的添加与删除都是系统自动控制,无需个人干预。
2、元数据锁和表锁的操纵对象不同,但表的数据是由表的结构决定的,因此在执行DML语句的时候也会触发对元素据对象加锁。几种常见的元素据锁、触发条件还有兼容性关系如下表。
3、元数据锁的类型总结:
其实可以将元数据锁分为两类排他锁(EXCLUSIVE)和共享锁(SHARED),共享锁之间不会发生冲突,排他锁和共享锁之间会发生冲突。DML语句的执行会触发加共享锁,DDL语句的执行会触发加排他锁。其实也很好理解,对表中数据进行操作的时候不能修改表的结构,修改表的结构时候不能操纵表中数据。这里需要注意的是mysql的DDL语句是非事务的,即使为DDL语句添加了事务,DDL语句还是会自动提交,不会等到commit。如果执行了DDL语句后再执行DML语句则不会阻塞DML语句,因为DDL语句已经提交结果。
<3>意向锁
在加表锁之前除了判断这个表有没有加表锁之外还需要判断这个表有没有添加行锁,一行一行的判读有没有添加行锁太过耗时,于是就引入了意向锁。当加了行锁之后,就会对这个表加上意向锁。
1、意向共享锁(IS): 由语句select … lock in share mode添加 。与 表锁共享锁(read)兼容,与表锁排他锁(write)互斥。
2、意向排他锁(IX): 由insert、update、delete、select…for update添加 。与表锁共享锁(read)及排他锁(write)都互斥,意向锁之间不会互斥。
SQL | 行锁类型 |
---|---|
Insert,Update,Delete,Select … for update | 排他锁 |
Select | 不加锁 |
Select … lock in share mode | 共享锁 |
<2>间隙锁:
锁住记录间隙(不包括该记录)确保记录的间隙不变,防止其他事务向这个间隙插入数据产生幻读。
产生间隙锁的情况:索引上的等值查询(唯一索引),给不存在的记录加锁时, 优化为间隙锁。
比如,对键为33的数据加锁,它会锁住[39,44]之间的数据。当向这个范围插入数据时就会阻塞插入操作。
<3>临键锁(Next-Key Lock):行锁和间隙锁组合,锁住这个键值,并且锁住这个键值的后一键值的前面的间隙。
产生临键锁的情况:
1、对非唯一索引的某个键加锁。
比如,对18进行加锁,它或锁住[18,29)。这是因为索引是非唯一索引,仅仅锁住18是不够的,有可能在(18,29)之间再插入18。
2、对于范围查询(唯一索引和非唯一索引),锁住当前键及其后面所有的键以及无穷大。
比如id>=18,他会锁住[18,无穷)这区间的所有数据。
<1> 共享锁(读锁,S锁):一个事务加共享锁后,其他事务也可加共享锁,但不可加排他锁,在事务执行过程中可以释放共享锁。
<2>排他锁(写锁,X锁):一个事务加排他锁后,其他事务不能加任何锁,事务执行完后才可释放锁。
<1>读未提交:不加锁
<2>读已提交:读的时候加共享锁,读完后释放锁
<3>可重复读:加共享锁,事务执行完后才释放锁
<4>可串行化:读数据时添加表级共享锁,执行完后才释放
m-ids | 生成当前read view时活跃的事务id集合,也就是那些还没有提交的事务 |
---|---|
min-trx-id | m-ids中的最小值 |
max-trx-id | 分配给下一个事务的id,该事务还没有被创建或执行 |
creator-id | 创建当前视图的事务的id |
<1>实现读已提交(RC)
读数据时,从版本链的最新记录和所有历史版本中从上到下一找到第一个DB_TRX_ID满足以下条件的版本的数据:
DB_TRX_ID = creator-id 或 DB_TRX_ID < min-trx-id 或 min-trx-id= DB_TRX_ID < max-trx-id并且DB_TRX_ID不在m-ids中。
<2>原理:原理很简单,读未提交事务修改的数据造成了读未提交,只要我们不去读未提交事务修改的数据就可以了,上面的几个条件其实也就是过滤掉了未提交事务修改的数据。但是这并没有解决不可重复读,因为每次读操作生成的read view都是不同的。
<3>实现可重复读(RR)
在<1>的基础上,限制事务只生成一个read view,在第一读之后,后续的读操作都取第一次的read view。但是这并没有解决幻读,因为这里限制的都是对同一条数据的读写。
<4>可串行化
在<3>的基础上添加间隙锁,锁住读操作需要操作的范围,禁止在读的时候向这个范围内添加数据。
mysql> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin | ON |
+---------------+-------+
2、开启Binlog,修改my.cnf或my.ini配置文件,在[mysqld]下面增加如下命令
#开启log-bin
log-bin=ON
#binglog文件名序列号前面的值
log-bin-basename=mysqlbinlog
#Binlog记录模式
binlog-format=ROW
或者使用下面语句
binlog-format=ROW
#开启并执行binglog文件名序列号前面的值
log-bin=mysqlbinlog
3、使用mysql语句显示binlog的相关信息
#显示有哪些binlog文件
mysql>show binary logs; //等价于show master logs;
#显示binlog文件的状态
mysql>show master status;
#显示binlog文件中的事件
mysql>show binlog events;
#显示特定binlog文件中的事件
mysql>show binlog events in 'mysqlbinlog.000001';
4、通过mysqlbinlog命令查询binlog文件中的内容,注意mysqlbinlog命令与mysql命令同级,需要放在命令行中执行。
#查看文件内容,以字符显示(不能直接查看二进制文件)
mysqlbinlog --no-defaults "文件名"
#将显示的内容存储为文件
mysqlbinlog --no-defaults "文件名" > "test.sql"
5、使用mysqlbinlog Binlog恢复数据
//按指定时间恢复
mysqlbinlog --start-datetime="2020-04-25 18:00:00" --stopdatetime="2020-04-26 00:00:00" mysqlbinlog.000002 | mysql -uroot -p1234
//按事件位置号恢复
mysqlbinlog --start-position=154 --stop-position=957 mysqlbinlog.000002 | mysql -uroot -p1234
6、删除Binlog文件
purge binary logs to 'mysqlbinlog.000001'; //删除指定文件
purge binary logs before '2020-04-28 00:00:00'; //删除指定时间之前的文件
reset master; //清除所有文件
7、Redo Log和Binlog区别
Redo Log是属于InnoDB引擎功能,Binlog是属于MySQL Server自带功能,并且是以二进制
文件记录。
Redo Log属于物理日志,记录该数据页更新状态内容,Binlog是逻辑日志,记录更新过程。
Redo Log日志是循环写,日志空间大小是固定,Binlog是追加写入,写完一个写下一个,不
会覆盖使用。
Redo Log作为服务器异常宕机后事务数据自动恢复使用,Binlog可以作为主从复制和数据恢
复使用。Binlog没有自动crash-safe能力。
show [session|global] status
可以查看服务器状态信息#查看select语句的执行次数
show global status like 'Com_select';
#查看insert语句的执行次数
show global status like 'Com_insert';
....
#查看所有命令的执行次数
show global status like 'Com_%';
show variables like slow_query_log
。默认未开启。/etc/my.cnf
文件,添加如下两条配置#开启慢查询日志
slow_query_log=1;
#设置查询时间,只有超过阈值的查询语句才会被记录在慢查询日志文件中
long_query_time=2;
<3>重启MySQL
systemctl restart mysqld
<4>查看慢查询日志的内容
/var/lib/mysql/localhost-slow.log
select @@have_profiling;
查看是否执行profileset profiling=1;
开启profile#查看每条语句及其id
show profiles;
#根据id查看具体的一条语句的执行时间
show profile for query query_id;
#查看cpu使用情况
show profile cpu for query query_id;
explain select * from tb_user;
字段 | 含义 |
---|---|
id | 查询序列号,表示查询语句执行的顺序(一个查询可能包含子查询等),如果序号相同则从上到下执行,如果不同序列号大的查询语句先执行 |
select_type | select语句的类型,一个select语句中可能包含子查询等多个查询语句。常见类型有SIMPLE(不包含只查询,只有一个查询语句),PRIMARY(主查询即最外层查询语句),UNION(union中的第二个查询语句),SUBQUERY(子查询) |
type | 连接类型,即扫描方式。常见的有(从慢到快),system(系统表,少量数据,往往不需要磁盘IO),constant(常量连接,命中主键或者唯一索引,并且where的判断条件中的值为常量),eq_ref(主键索引或者唯一索引的等值查询,不要求查询条件为常量),ref(非主键,非唯一索引等值查询),range(索引上的范围查询),index(索引的全部扫描,不需要回表),all(全表扫描) |
possible_key | 可能使用到的索引 |
key | 实际使用到的索引 |
key_len | 使用到的索引的长度(索引所在column的长度的和) |
rows | MySQL认为查询必须要执行查询的行数,是个估计值 |
filtered | 返回结果的行数占读取的行数的百分比 |
Extra | Using filesort:没有使用索引进行排序,会使用quicksort进行排序,如果待排序数据大于sort_buffer_size,就会将数据分块并存储在文件中,然后再合并这些分块,一般用于order by、group by,Using temporary:创建临时表对数据进行排序(可能使用内存,也可能使用磁盘,一般用于group by),Using index:使用了覆盖索引,无需回表,Using where使用了where过滤(在使用存储引擎得到数据后需要在server层在对where条件进行过滤),Using index condition:使用索引,但仅靠索引无法得出全部数据,需要进行回表查询,Using where; Using index:如果同时出现 Using where; Using index 也是依赖索引、不需要回表查询,但由于是范围查询,需要进行过滤,null:上面的几种情况(不仅限于上面的几种情况)都没有使用到,但null不一定就代表性能不好,比如使用了索引但存在回表查询就是null |
https://www.cnblogs.com/benbenhan/articles/13212861.html
https://blog.csdn.net/sz85850597/article/details/91907988
https://blog.csdn.net/belalds/article/details/80728354
id | name |
---|---|
12 | b |
13 | a |
16 | g |
17 | f |
<1>主键索引,二者都采用了B+树,Innodb是聚簇索引,MyISAM是非聚簇索引。Innodb叶节点直接存储行,MyISAM存放行的地址。(注意下面的两幅图叶子节点与非叶子节点的数字都是表的key)
<2>用户创建的索引。MyISAM的结构与主键索引一致,而对于Ioondb,它的叶子节点的值存放的是主键值。在查询到主键值后,还需要去主键索引上根据id值查找到对于的表中的行,这一步叫做回表。而MyISAM不需要回表。
'%name
会失效,这与<3>类似在取出所有数据前都不知道是否满足模糊匹配条件,但'name%
不会失效。这里的失效指的是当前列是否会失效,无论哪种情况后面的列都会失效,这与<1>类似。create index idx_xxxx on table_name(column(n)) ;
<2>确定长度(n的值):使用如下语句查看区分度,选择合适的区分度
select count(distinct substring(email, 1, 2))/count(*) from tb_user;
https://www.cnblogs.com/gered/p/12210055.html#_label1_0
explain select * from tb_user use/ignore/force/ index(idx_user_pro) where profession = '软件工程';
insert into tb_test values(1,'tom');
insert into tb_test values(2,'cat');
insert into tb_test values(3,'jerry');
.....
<1>批量插入
insert into tb_test values (1,'tom'),(2,'cat'),(3,'jerry');
<2>手动控制事务,将多条插入语句作为一个事务提交
start transaction;
insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');
insert into tb_test values(4,'Tom'),(5,'Cat'),(6,'Jerry');
insert into tb_test values(7,'Tom'),(8,'Cat'),(9,'Jerry');
commit;
<3>主键按顺序插入,避免乱序插入。
<4>大批量插入数据使用load命令,而非insert
#连接数据库时添加--local-infile参数
mysql --local-infile -u root -p
#开启从本地文件加载数据
set global local-infile = 1;
#加载数据,fields terminated by ','表示以','分割字段,lines terminated by '/n'表示以换行分割记录
load data local-infile '文件路径' into table 表名 fields terminated by ',' lines terminated by '/n';
create index idx_user_age_phone_aa on tb_user(age,phone);
<2>如果order by的两个字段一个升序一个降序就会使用文件排序,而两个同时为升序或者两个同时为降序就会使用索引。这时因为取出的数据都是先按照第一个字段升序排序然后按照第二个字段升序排序,如果order by中两个字段全为升序则直接使用取出的数据即可,如果两个字段全为降序则反向读取叶子节点中的数据即可,如果一个升序一个降序无论正向读取还是反向读取都无法满足条件,只能重新进行排序。
在上面的例子中,我们都强制使用索引,如果不强制使用索引innodb会使用使用全表扫描。因为上面的例子都需要回表,innodb认为全表扫描然后进行排序效率更高。如果索引覆盖,则不会发生这种情况。
<3>如果一个升序,一个降序则创建索引时就应该指定升序还是降序。
<4> 如果不可避免的出现filesort,大数据量排序时,可以适当增大排序缓冲区大小sort_buffer_size(默认256k)。
explain select * from tb_sku t , (select id from tb_sku order by id limit 2000000,10) a where t.id = a.id;
#10 rows in set (5.38 sec)
select * from tb_sku limit 9000000, 10;
#10 rows in set (8.24 sec)
mysql不支持如下方式
#创建索引
create index idx_tb_sku_name on tb_sku(name);
查看三种方式的执行计划,发现它们都没有使用主键索引
查看使用主键索引和普通索引的执行时间,发现走主键索引会远远慢于普通索引
<2>count(字段),如果这个字段设置了索引则会走索引,如果没有设置索引则不会走索引。如果这个字段设置了not null,在server层不会进行判断是否为空的操作,如果没有设置not null,查询结果返回给server层后会进行判空操作。
<3>几种方式的执行速度:
c o u n t ( 字段 ) < c o u n t ( 主键 ) < c o u n t ( 1 ) ≈ c o u n t ( ∗ ) count(字段)
<4>MyISAM中的count()
MyISAM将表的列数存放在了磁盘上,在执行count()时直接去取即可。但对于innodb,支持事务,在并发的情况下会出现表的列数不一致的情况。
https://www.jianshu.com/p/5143b4d99376