-
mysql的分页比较简单,只需要limit offset ,length就可以获取数据了,但是当offset和length比较大的时候,mysql明显性能下降1.子查询优化法先找出第一条数据,然后大于等于这条数据的id就是要获取的数据缺点:数据必须是连续的,可以说不能有where条件,where条件会筛选数据,导致数据失去连续性,具体方法请看下面的查询实例:mysql> set profiling=1; Query OK, 0 rows affected (0.00 sec) mysql> select count(*) from Member; +----------+ | count(*) | +----------+ | 169566 | +----------+ 1 row in set (0.00 sec) mysql> pager grep !~- PAGER set to 'grep !~-' mysql> select * from Member limit 10, 100; 100 rows in set (0.00 sec) mysql> select * from Member where MemberID >= (select MemberID from Member limit 10,1) limit 100; 100 rows in set (0.00 sec) mysql> select * from Member limit 1000, 100; 100 rows in set (0.01 sec) mysql> select * from Member where MemberID >= (select MemberID from Member limit 1000,1) limit 100; 100 rows in set (0.00 sec) mysql> select * from Member limit 100000, 100; 100 rows in set (0.10 sec) mysql> select * from Member where MemberID >= (select MemberID from Member limit 100000,1) limit 100; 100 rows in set (0.02 sec) mysql> nopager PAGER set to stdout mysql> show profiles\G *************************** 1. row *************************** Query_ID: 1 Duration: 0.00003300 Query: select count(*) from Member *************************** 2. row *************************** Query_ID: 2 Duration: 0.00167000 Query: select * from Member limit 10, 100 *************************** 3. row *************************** Query_ID: 3 Duration: 0.00112400 Query: select * from Member where MemberID >= (select MemberID from Member limit 10,1) limit 100 *************************** 4. row *************************** Query_ID: 4 Duration: 0.00263200 Query: select * from Member limit 1000, 100 *************************** 5. row *************************** Query_ID: 5 Duration: 0.00134000 Query: select * from Member where MemberID >= (select MemberID from Member limit 1000,1) limit 100 *************************** 6. row *************************** Query_ID: 6 Duration: 0.09956700 Query: select * from Member limit 100000, 100 *************************** 7. row *************************** Query_ID: 7 Duration: 0.02447700 Query: select * from Member where MemberID >= (select MemberID from Member limit 100000,1) limit 100从结果中可以得知,当偏移1000以上使用子查询法可以有效的提高性能。2.倒排表优化法倒排表法类似建立索引,用一张表来维护页数,然后通过高效的连接得到数据缺点:只适合数据数固定的情况,数据不能删除,维护页表困难倒排表介绍:(而倒排索引具称是搜索引擎的算法基石)倒排表是指存放在内存中的能够追加倒排记录的倒排索引。倒排表是迷你的倒排索引。临时倒排文件是指存放在磁盘中,以文件的形式存储的不能够追加倒排记录的倒排索引。临时倒排文件是中等规模的倒排索引。最终倒排文件是指由存放在磁盘中,以文件的形式存储的临时倒排文件归并得到的倒排索引。最终倒排文件是较大规模的倒排索引。倒排索引作为抽象概念,而倒排表、临时倒排文件、最终倒排文件是倒排索引的三种不同的表现形式。3.反向查找优化法当偏移超过一半记录数的时候,先用排序,这样偏移就反转了缺点:order by优化比较麻烦,要增加索引,索引影响数据的修改效率,并且要知道总记录数 ,偏移大于数据的一半limit偏移算法:正向查找: (当前页 - 1) * 页长度反向查找: 总记录 - 当前页 * 页长度做下实验,看看性能如何总记录数:1,628,775每页记录数: 40总页数:1,628,775 / 40 = 40720中间页数:40720 / 2 = 20360第21000页正向查找SQL:SELECT * FROM `abc` WHERE `BatchID` = 123 LIMIT 839960, 40时间:1.8696 秒反向查找sql:SELECT * FROM `abc` WHERE `BatchID` = 123 ORDER BY InputDate DESC LIMIT 788775, 40时间:1.8336 秒第30000页正向查找SQL: SELECT * FROM `abc` WHERE `BatchID` = 123 LIMIT 1199960, 40时间:2.6493 秒反向查找sql:把limit偏移量限制低于某个数。。超过这个数等于没数据,我记得alibaba的dba说过他们是这样做的5.只查索引法MySQL的limit工作原理就是先读取n条记录,然后抛弃前n条,读m条想要的,所以n越大,性能会越差。优化前SQL:SELECT * FROM member ORDER BY last_active LIMIT 50,5优化后SQL:SELECT * FROM member INNER JOIN (SELECT member_id FROM member ORDER BY last_active LIMIT 50, 5) USING (member_id)区别在于,优化前的SQL需要更多I/O浪费,因为先读索引,再读数据,然后抛弃无需的行。而优化后的SQL(子查询那条)只读索引(Cover index)就可以了,然后通过member_id读取需要的列。
-
2020中国MySQL用户组华为云专场:数字驱动技术创新,云领未来11月18日下午,由ACMUG中国MySQL用户组主办的 “华为云专场” 技术沙龙在北京举行。大会采取线下沙龙与线上直播相结合的形式,线上由华为云数据库多位技术专家共同分享核心产品GaussDB的关键技术与客户实践,线下由华为云数据库业务总裁苏光牛与众多业界专家共同探讨云数据库热点问题,并对云数据库核心能力及未来发展方向做了深度探讨。数字化时代,技术创新是主旋律,未来云数据库的发展必然是基于技术创新来实现。华为云数据库多位技术专家在线上直播分享了华为云重磅产品GaussDB数据库的最新技术能力与竞争优势,如GaussDB(for MySQL)针对数据分析场景提供了并行查询、近数据下推功能,针对电商场景提供热点更新优化等,以及针对云数据库发展现状及客户需求,分享了GaussDB的产品革新与客户实践,还对GaussDB社区及商业版的关键特性进行了分享,此外还结合客户实践讲述了GaussDB(for MySQL)从云化到Cloud Native的演进之路。线下闭门讨论会方面,华为云数据库业务总裁苏光牛与来自各大企业和社区的大咖们,就云数据库热点问题进行了广泛讨论和积极分享。苏光牛表示,未来云数据库会朝多元化、开放融合、云原生分布式方向发展,智能运维与自治数据库会大有可为,但同时也要不断进行产品和技术创新,解决数据库卡脖子的问题,推动云数据库跃迁式发展。ACMUG华为云专场数据库技术闭门讨论会现场图新基建时代,数字化转型正在驱动企业的不断云化,对云数据库的要求也水涨船高,谁能够吃透企业的现状,掌握最新技术能力,提供更新颖更个性化的服务,才会赢得更大的市场机会。而华为云的与时俱进与不断创新,为未来积蓄了巨大能量,也让它的未来之路越走越宽。 Ps:错过直播的小伙伴们,可点击链接回顾精彩内容:cid:link_0
-
在 MySQL 中,物理文件存放在数据目录中。数据目录与安装目录不同,安装目录用来存储控制服务器和客户端程序的命令,数据目录用来存储 MySQL 服务器在运行过程中产生的数据。本节主要介绍 MySQL 数据目录的物理结构和作用。 MySQL 中任何一项逻辑性或者物理性文件都具有可配置性,另外由于开源的原因,每个版本都有一些改进,所以我们在学习本节内容时要灵活掌握,不能生搬硬套。如果你不知道 MySQL 的数据目录路径,可以通过SHOW VARIABLES LIKE 'datadir';命令查看。下面分别讲解 MySQL 数据目录里存放的目录和文件。1. 数据目录下图是 MySQL(5.7.29)在 Windows 系统下安装的数据文件目录,可以看到有如下几类文件。Data 目录用来存放数据库相关的数据信息,包括数据库信息,表信息等。MySQL 5.7 及之后的版本开始支持集群模式,installer_config.xml 配置文件主要用于配置单节点或集群模式。my.ini 文件是 MySQL 服务端和客户端主要的配置文件,包括编码集、默认引擎、最大连接数等设置。MySQL 服务器启动时会默认加载此文件。2. Data目录Data 目录中存放的文件如下图所示:由图中可以看出,系统数据库和用户自定义数据库的存放路径相同。数据库目录中主要存放相应的数据库对象(图中箭头指向的为 test 数据库目录中存放的文件 )。对 Data 目录中的文件说明如下:mysql、performance_schema、sakila、sys 和 world 是系统数据库,information_schema 数据库比较特殊,这里没有相应的数据库目录。test 是用户自定义的数据库,也就是用户自己创建的数据库。auto.cnf:MySQL 服务器的选项文件,用于存储 server-uuid 的值。server-uuid 与 server-id 一样,用于标识 MySQL 实例在集群中的唯一性。ib_logfile0、ib_logfile1 是支持事务性引擎的 redo 日志文件ibdata1 为共享表空间(系统表空间)。如果采用 InnoDB 引擎,默认大小为 10M 。ibtmp1 为存储临时对象的空间,比如临时表对象等。数据目录里可能还有:MySQL 服务器的进程 ID(PID)文件。MySQL 服务器所生成的状态和日志文件。DES 密钥文件或服务器的 SSL 证书。3. 数据库目录数据库实际是一个目录,每个目录都保存着相应数据库中的表以及表数据。下面我们以 test 数据库为例讲解目录中存放的文件。 test 数据库中有如下几张数据表:+-------------------+ | Tables_in_test | +-------------------+ | tb_student | | tb_student_course | | tb_students_info | | tb_usertest | +-------------------+对 test 数据库目录中的文件说明如下:1)db.opt用来保存数据库的配置信息,比如该库的默认字符集编码和字符集排序规则。如果你创建数据库时指定了字符集和排序规则,后续创建的表没有指定字符集和排序规则,那么该表将采用 db.opt 文件中指定的属性。对于 InnoDB 表,如果是独立的表空间,数据库中的表结构以及数据都存储在数据库的路径下(而不是在共享表空间 ibdata1 文件中)。但是数据中的其他对象,包括数据被修改之后,事务提交之间的版本信息,仍然存储在共享表空间的 ibdata1 文件中。2).frm在 MySQL 中建立任何一张数据表,其对应的数据库目录下都会有该表的 .frm 文件。.frm文件用来保存每个数据表的元数据(meta)和表结构等信息。数据库崩溃时,可以用 .frm 文件恢复表结构。.frm 文件跟存储引擎无关,任何存储引擎的数据表都有 .frm 文件,命名方式为表名.frm,如 users.frm。MySQL 8.0 版本开始,frm 文件被取消,MySQL 把文件中的数据都写到了系统表空间。通过利用 InnoDB 存储引擎来实现表 DDL 语句操作的原子性(在之前版本中是无法实现表 DDL 语句操作的原子性的,如 TRUNCATE 无法回滚)。3).MYD和.MYI.MYD 理解为 My Data,用于存放 MyISAM 表的数据。.MYI 理解为 My Index,主要存放 MyISAM 表的索引及相关信息。4).ibd对于 InnoDB 存储引擎的数据表,一个表对应两个文件,一个是 *.frm,存储表结构信息;一个是*.ibd,存储表中数据。5).ibd和.ibdata.ibd 和 .ibdata 都是专属于 InnoDB 存储引擎的数据库文件。当采用共享表空间时,所有 InnoDB 表的数据均存放在 .ibdata 中。所以当表越来越多时,这个文件会变得很大。相对应的 .ibd 就是采用独享表空间时 InnoDB 表的数据文件。当然,就算开启了独享表空间,ibdata 文件也会越来越大,因为这个文件里还存储了:变更缓冲区双写缓冲区撤销日志
-
尊敬的华为云客户:为了进一步提升RDS MySQL服务的稳定性和可靠性,华为云计划于2020/11/22 对RDS MySQL实例进行升级,升级详情如下:升级时间影响区域影响服务升级影响2020/11/22 03:00-06:00(北京时间)华东-上海一RDS MySQL升级过程中RDS MySQL实例将会出现1~2次闪断,每次闪断小于3秒如您有RDS MySQL实例不中断操作的需求,请您避开升级时间段,并关注业务运行情况。给您带来的不便,敬请谅解。感谢您对华为云的支持!
-
1、首先。临时表是session级别的,当前session创建的表,在其他session中看不到。session 1:mysql> create temporary table test3 (id_tmp int)engine=innodb; Query OK, 0 rows affected (0.00 sec)session 2:mysql> show create table test3\G ERROR 1146 (42S02): Table 'test.test3' doesn't exist2、临时表在session中,可以和正式的表重名。mysql> create table test2 (id int)engine=innodb; Query OK, 0 rows affected (0.01 sec) mysql> create temporary table test2 (id_tmp int)engine=innodb; Query OK, 0 rows affected (0.00 sec)3、当数据库中物理表和临时表的时候,使用show create table查看的是临时表的内容:mysql> show create table test2\G *************************** 1. row *************************** Table: test2 Create Table: CREATE TEMPORARY TABLE `test2` ( `id_tmp` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec)4、临时表drop掉之后,show create table查看的是物理表的内容。mysql> show tables like "test2"; +------------------------+ | Tables_in_test (test2) | +------------------------+ | test2 | +------------------------+ 1 row in set (0.00 sec) mysql> drop table test2; Query OK, 0 rows affected (0.00 sec) mysql> show tables like "test2"; +------------------------+ | Tables_in_test (test2) | +------------------------+ | test2 | +------------------------+ 1 row in set (0.00 sec)5、show tables命令,不能看到临时表。6、不同的session中可以创建同名的临时表。7、临时表保存方法 在MySQL中,使用.frm来保存表结构,而使用.ibd来保存表数据,.frm文件一般是放在tmpdir这个参数指定的目录下面的。台式机windows平台下MySQL的如下:mysql> show variables like "%tmpdir%"; +-------------------+-------------------------------------------------+ | Variable_name | Value | +-------------------+-------------------------------------------------+ | innodb_tmpdir | | | slave_load_tmpdir | C:\WINDOWS\SERVIC~1\NETWOR~1\AppData\Local\Temp | | tmpdir | C:\WINDOWS\SERVIC~1\NETWOR~1\AppData\Local\Temp | +-------------------+-------------------------------------------------+ 3 rows in set, 1 warning (0.01 sec) MySQL5.6版本下,会生成一个.ibd的文件来保存临时表。MySQL5.7版本下,引入了临时文件表空间,专门用来存放临时文件的数据。当我们使用不同的session来创建相同名称的临时表的时候,会发现临时表的目录下面存在不同名称的临时表文件:这些临时表在内存中是通过链表的方式来表示的,如果一个session中包含两个临时表,MySQL会创建一个临时表的链表,将这两个临时表连接起来,实际的操作逻辑中,如果我们执行了一条SQL,MySQL会遍历这个临时表的链表,检查是否有这个SQL中指定表名字的临时表,如果有临时表,优先操作临时表,如果没有临时表,则操作普通的物理表。8、临时表在主从复制中的注意点临时表由于是session级别的,那么在session退出的时候,是会删除临时表的。但是主节点中并没有对临时表进行显示的操作,而是关闭session即可删除,那么从节点如何知道什么时候才能删除临时表呢?假设主节点进行如下SQL:crete table tbl; create temporary table tmp like tbl; insert into tmp values (0,0); insert into tbl select * from tmp;9、不同线程的同名临时表在从库上如何同时存在? 我们知道临时表是session级别的,而且不同session之间的临时表可以重名,在从库进行binlog回放的时候,从库是如何知道这些重名的临时表分别属于哪个事务的呢? 这个概念的理解可以参考函数中的形参和实参的概念,形参和实参可能有同样的名字,进行赋值的时候,二者的指针值是不一样的,所以同名的参数,对编译器来讲,由于指针值不一样,所以不会出现错误。 MySQL维护数据表,除了物理上要有文件外,内存里面也有一套机制区别不同的表,每个表都对应一个table_def_key。而这个table_def_key的值是由"库名字+表名字+server_id+thread_id"组成的,因为thread_id不同,所以在从库中进行操作的时候,是不会冲突的。
-
在MySQL中,我们经常需要创建用户和删除用户,创建用户时,我们一般使用create user或者grant语句来创建,create语法创建的用户没有任何权限,需要再使用grant语法来分配权限,而grant语法创建的用户直接拥有所分配的权限。在一些测试用户创建完成之后,做完测试,可能用户的生命周期就结束了,需要将用户删除,而删除用户在MySQL中一般有两种方法,一种是drop user,另外一种是delete from mysql.user,那么这两种方法有什么区别呢?我们这里通过例子演示。delete from mysql.user首先,我们看看delete from mysql.user的方法。我们创建两个用户用来测试,测试环境是MySQL5.5版本,用户名分别为yeyz@'%'和yeyz@'localhost',创建用户的语法如下:mysql 15:13:12>>create user yeyz@'%' identified by '123456'; Query OK, rows affected (. sec) mysql 15:20:01>>grant select,create,update,delete on yeyz.yeyz to yeyz@'%'; Query OK, rows affected (. sec) mysql 15:29:48>>GRANT USAGE ON yeyz.yeyz TO 'yeyz'@localhost IDENTIFIED BY '123456'; Query OK, rows affected (. sec) mysql--dba_admin@127...1:(none) 15:20:39>>show grants for yeyz@'%'; +-----------------------------------------------------------------------------------------------------+ | Grants for yeyz@% | +-----------------------------------------------------------------------------------------------------+ | GRANT USAGE ON *.* TO 'yeyz'@'%' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' | | GRANT SELECT, UPDATE, DELETE, CREATE ON `yeyz`.`yeyz` TO 'yeyz'@'%' | +-----------------------------------------------------------------------------------------------------+此时我们通过delete的方法手动删除mysql.user表中的这两个用户,在去查看用户表,我们发现:mysql 15:20:43>>delete from mysql.user where user='yeyz'; Query OK, rows affected (. sec) mysql 15:21:40>>select user,host from mysql.user; +------------------+-----------------+ | user | host | +------------------+-----------------+ | dba_yeyz | localhost | | root | localhost | | tkadmin | localhost | +------------------+-----------------+ rows in set (. sec)已经没有这两个yeyz的用户了,此时我们使用show grants for命令查看刚才删除的用户,我们发现依旧是存在这个用户的权限说明的:mysql 15:24:21>>show grants for yeyz@'%'; +-----------------------------------------------------------------------------------------------------+ | Grants for yeyz@% | +-----------------------------------------------------------------------------------------------------+ | GRANT USAGE ON *.* TO 'yeyz'@'%' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9' | | GRANT SELECT, UPDATE, DELETE, CREATE ON `yeyz`.`yeyz` TO 'yeyz'@'%' | +-----------------------------------------------------------------------------------------------------+ rows in set (0.00 sec)说明我们虽然从mysql.user表里面删除了这个用户,但是在db表和权限表里面这个用户还是存在的,为了验证这个结论,我们重新创建一个yeyz@localhost的用户,这个用户我们只给它usage权限,其他的权限我们不配置,如下:mysql ::>>GRANT USAGE ON yeyz.yeyz TO 'yeyz'@localhost IDENTIFIED BY '123456'; Query OK, rows affected (. sec)这个时候,我们使用yeyz@localhost这个用户去登陆数据库服务,然后进行相关的update操作,如下:[dba_mysql@tk-dba-mysql-stat-- ~]$ /usr/local/mysql/bin/mysql -uyeyz --socket=/data/mysql_4306/tmp/mysql.sock --port= -p -hlocalhost Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is Server version: 5.5.-log MySQL Community Server (GPL) Copyright (c) , , Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql--yeyz@localhost:(none) 15:31:05>>select * from yeyz.yeyz; +------+ | id | +------+ | 3 | | 4 | | 5 | +------+ rows in set (. sec) mysql--yeyz@localhost:(none) 15:31:16>>delete from yeyz.yeyz where id=; Query OK, row affected (. sec) mysql--yeyz@localhost:(none) 15:31:32>>select * from yeyz.yeyz; +------+ | id | +------+ | 3 | | 4 | +------+ rows in set (. sec)最终出现的结果可想而知,一个usage权限的用户,对数据库总的表进行了update操作,而且还成功了。这一切得益于我们delete from mysql.user的操作,这种操作虽然从user表里面删除了记录,但是当这条记录的host是%时,如果重新创建一个同名的新用户,此时新用户将会继承以前的用户权限,从而使得用户权限控制失效,这是很危险的操作,尽量不要执行。再开看看drop的方法删除用户首先,我们删除掉刚才的那两个用户,然后使用show grants for语句查看他们的权限:mysql ::>>drop user yeyz@'%'; Query OK, rows affected (0.00 sec) mysql ::>>drop user yeyz@'localhost'; Query OK, rows affected (0.00 sec) mysql ::>> mysql ::>>show grants for yeyz@'%'; ERROR (): There is no such grant defined for user 'yeyz' on host '%' mysql ::>>show grants for yeyz@'localhost'; ERROR (): There is no such grant defined for user 'yeyz' on host '192.168.18.%'可以看到,权限已经完全删除了,此时我们重新创建一个只有select权限的用户:mysql ::>>GRANT SELECT ON *.* TO 'yeyz'@'localhost' IDENTIFIED BY PASSWORD '*6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9'; Query OK, rows affected (. sec)我们使用这个用户登录到数据库服务,然后尝试进行select、update以及create操作,结果如下:[dba_mysql@tk-dba-mysql-stat-10-104 ~]$ /usr/local/mysql/bin/mysql -uyeyz --socket=/data/mysql_4306/tmp/mysql.sock --port=4306 -p -hlocalhost Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is Server version: 5.5.19-log MySQL Community Server (GPL) Copyright (c) , , Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql ::>>select * from yeyz.yeyz; +------+ | id | +------+ | | | | | | +------+ rows in set (0.00 sec) mysql ::>>update yeyz.yeyz set id= where id=; ERROR (): UPDATE command denied to user 'yeyz'@'localhost' for table 'yeyz' mysql ::>>create table test (id int); ERROR (D000): No database selected mysql ::>>create table yeyz.test (id int); ERROR (): CREATE command denied to user 'yeyz'@'localhost' for table 'test'可以发现,这个用户只可以进行select操作,当我们尝试进行update操作和create操作的时候,系统判定这种操作没有权限,直接拒绝了,这就说明使用drop user方法删除用户的时候,会连通db表和权限表一起清除,也就是说删的比较干净,不会对以后的用户产生任何影响。结论:当我们想要删除一个用户的时候,尽量使用drop user的方法删除,使用delete方法可能埋下隐患,下次如果创建同名的用户名时,权限控制方面存在一定的问题。这个演示也解决了一些新手朋友们的一个疑问:为什么我的用户只有usage权限,却能访问所有数据库,并对数据库进行操作?这个时候,你需要看看日志,查询自己有没有进行过delete from mysql.user的操作,如果有,这个问题就很好解释了。
-
索引可以提高查询的速度,但并不是使用带有索引的字段查询时,索引都会起作用。使用索引有几种特殊情况,在这些情况下,有可能使用带有索引的字段查询时,索引并没有起作用,下面重点介绍这几种特殊情况。1. 查询语句中使用LIKE关键字在查询语句中使用 LIKE 关键字进行查询时,如果匹配字符串的第一个字符为“%”,索引不会被使用。如果“%”不是在第一个位置,索引就会被使用。例 1为了便于理解,我们先查询 tb_student 表中的数据,SQL 语句和运行结果如下:mysql> SELECT * FROM tb_student; +----+------+------+------+ | id | name | age | sex | +----+------+------+------+ | 1 | 张三 | 12 | 男 | | 2 | 李四 | 12 | 男 | | 3 | 王五 | 13 | 女 | | 4 | 张四 | 13 | 女 | | 5 | 王四 | 15 | 男 | | 6 | 赵六 | 12 | 女 | +----+------+------+------+ 6 rows in set (0.03 sec)下面在查询语句中使用 LIKE 关键字,且匹配的字符串中含有“%”符号,使用 EXPLAIN 分析查询情况,SQL 语句和运行结果如下:mysql> EXPLAIN SELECT * FROM tb_student WHERE name LIKE '%四'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: tb_student partitions: NULL type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 6 filtered: 16.67 Extra: Using where 1 row in set, 1 warning (0.01 sec) mysql> CREATE INDEX index_name ON tb_student(name); Query OK, 6 rows affected (0.13 sec) mysql> EXPLAIN SELECT * FROM tb_student WHERE name LIKE '李%'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: tb_student partitions: NULL type: range possible_keys: index_name key: index_name key_len: 77 ref: NULL rows: 1 filtered: 100.00 Extra: Using index condition 1 row in set, 1 warning (0.00 sec)第一个查询语句执行后,rows 参数的值为 6,表示这次查询过程中查询了 6 条记录;第二个查询语句执行后,rows 参数的值为 1,表示这次查询过程只查询 1 条记录。同样是使用 name 字段进行查询,因为第一个查询语句的 LIKE 关键字后的字符串是以“%”开头的,所以第一个查询语句没有使用索引,而第二个查询语句使用了索引 index_name。2. 查询语句中使用多列索引多列索引是在表的多个字段上创建一个索引,只有查询条件中使用了这些字段中的第一个字段,索引才会被使用。例 2在 name 和 age 两个字段上创建多列索引,并验证多列索引的使用情况,SQL 语句和运行结果如下:mysql> CREATE INDEX index_name_age ON tb_student(name,age); Query OK, 6 rows affected (0.11 sec) mysql> EXPLAIN SELECT * FROM tb_student WHERE name LIKE '李%'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: tb_student partitions: NULL type: range possible_keys: index_name_age key: index_name_age key_len: 77 ref: NULL rows: 1 filtered: 100.00 Extra: Using index condition 1 row in set, 1 warning (0.05 sec) mysql> EXPLAIN SELECT * FROM tb_student WHERE age LIKE '12'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: tb_student partitions: NULL type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 6 filtered: 16.67 Extra: Using where 1 row in set, 1 warning (0.00 sec)第一条查询语句的查询条件使用了 name 字段,分析结果显示 rows 参数的值为 1,且查询过程中使用了 index_name_age 索引。第二条查询语句的查询条件使用了 age 字段,结果显示 rows 参数的值为 6,且 key 参数的值为 NULL,这说明第二个查询语句没有使用索引。因为 name 字段是多列索引的第一个字段,所以只有查询条件中使用了 name 字段才会使 index_name_age 索引起作用。3. 查询语句中使用OR关键字查询语句只有 OR 关键字时,如果 OR 前后的两个条件的列都是索引,那么查询中将使用索引。如果 OR 前后有一个条件的列不是索引,那么查询中将不使用索引。例 3下面演示 OR 关键字的使用。mysql> EXPLAIN SELECT * FROM tb_student WHERE name='张三' or sex='男'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: tb_student partitions: NULL type: ALL possible_keys: index_name,index_name_age key: NULL key_len: NULL ref: NULL rows: 6 filtered: 30.56 Extra: Using where 1 row in set, 1 warning (0.06 sec) mysql> EXPLAIN SELECT * FROM tb_student WHERE name='张三' or id='12'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: tb_student partitions: NULL type: index_merge possible_keys: PRIMARY,index_name,index_name_age key: index_name,PRIMARY key_len: 77,4 ref: NULL rows: 2 filtered: 100.00 Extra: Using union(index_name,PRIMARY); Using where 1 row in set, 1 warning (0.01 sec)由于 sex 字段没有索引,所以第一条查询语句没有使用索引;name 字段和 id 字段都有索引,所以第二条查询语句使用了 index_name 和 PRIMARY 索引 。总结使用索引查询记录时,一定要注意索引的使用情况。例如,LIKE 关键字配置的字符串不能以“%”开头;使用多列索引时,查询条件必须要使用这个索引的第一个字段;使用 OR 关键字时,OR 关键字连接的所有条件都必须使用索引。
-
JSON 格式字段是 Mysql 5.7 新加的属性,不够它本质上以字符串性质保存在库中的,刚接触时我只了解 $.xx 查询字段的方法,因为大部分时间,有这个就够了JSON_EXTRACT(json_doc [,path])查询字段mysql> set @j = '{"name":"wxnacy"}'; mysql> select JSON_EXTRACT(@j, '$.name'); +----------------------------+ | JSON_EXTRACT(@j, '$.name') | +----------------------------+ | "wxnacy" | +----------------------------+还有一种更简洁的方式,但是只能在查询表时使用mysql> select ext -> '$.name' from test; +-----------------+ | ext -> '$.name' | +-----------------+ | "wxnacy" | +-----------------+在 $. 后可以正常的使用 JSON 格式获取数据方式,比如数组mysql> set @j = '{"a": [1, 2]}'; mysql> select JSON_EXTRACT(@j, '$.a[0]'); +----------------------------+ | JSON_EXTRACT(@j, '$.a[0]') | +----------------------------+ | 1 | +----------------------------+JSON_DEPTH(json_doc)计算 JSON 深度,计算方式 {} [] 有一个符号即为一层,符号下有数据增加一层,复杂 JSON 算到最深的一次为止,官方文档说 null 值深度为 0,但是实际效果并非如此,列举几个例子JSON_LENGTH(json_doc [, path])计算 JSON 最外层或者指定 path 的长度,标量的长度为1。数组的长度是数组元素的数量,对象的长度是对象成员的数量。mysql> SELECT JSON_LENGTH('[1, 2, {"a": 3}]'); +---------------------------------+ | JSON_LENGTH('[1, 2, {"a": 3}]') | +---------------------------------+ | 3 | +---------------------------------+ mysql> SELECT JSON_LENGTH('{"a": 1, "b": {"c": 30}}'); +-----------------------------------------+ | JSON_LENGTH('{"a": 1, "b": {"c": 30}}') | +-----------------------------------------+ | 2 | +-----------------------------------------+ mysql> SELECT JSON_LENGTH('{"a": 1, "b": {"c": 30}}', '$.b'); +------------------------------------------------+ | JSON_LENGTH('{"a": 1, "b": {"c": 30}}', '$.b') | +------------------------------------------------+ | 1 | +------------------------------------------------+JSON_TYPE(json_doc)返回一个utf8mb4字符串,指示JSON值的类型。 这可以是对象,数组或标量类型,如下所示:mysql> SET @j = '{"a": [10, true]}'; mysql> SELECT JSON_TYPE(@j); +---------------+ | JSON_TYPE(@j) | +---------------+ | OBJECT | +---------------+ mysql> SELECT JSON_TYPE(JSON_EXTRACT(@j, '$.a')); +------------------------------------+ | JSON_TYPE(JSON_EXTRACT(@j, '$.a')) | +------------------------------------+ | ARRAY | +------------------------------------+ mysql> SELECT JSON_TYPE(JSON_EXTRACT(@j, '$.a[0]')); +---------------------------------------+ | JSON_TYPE(JSON_EXTRACT(@j, '$.a[0]')) | +---------------------------------------+ | INTEGER | +---------------------------------------+ mysql> SELECT JSON_TYPE(JSON_EXTRACT(@j, '$.a[1]')); +---------------------------------------+ | JSON_TYPE(JSON_EXTRACT(@j, '$.a[1]')) | +---------------------------------------+ | BOOLEAN | +---------------------------------------+可能的返回类型纯JSON类型:OBJECT:JSON对象ARRAY:JSON数组BOOLEAN:JSON真假文字NULL:JSON null文字数字类型:INTEGER:MySQL TINYINT,SMALLINT,MEDIUMINT以及INT和BIGINT标量DOUBLE:MySQL DOUBLE FLOAT标量DECIMAL:MySQL DECIMAL和NUMERIC标量时间类型:DATETIME:MySQL DATETIME和TIMESTAMP标量日期:MySQL DATE标量TIME:MySQL TIME标量字符串类型:STRING:MySQL utf8字符类型标量:CHAR,VARCHAR,TEXT,ENUM和SET二进制类型:BLOB:MySQL二进制类型标量,包括BINARY,VARBINARY,BLOB和BIT所有其他类型:OPAQUE(原始位)JSON_VALID返回0或1以指示值是否为有效JSON。 如果参数为NULL,则返回NULL。mysql> SELECT JSON_VALID('{"a": 1}'); +------------------------+ | JSON_VALID('{"a": 1}') | +------------------------+ | 1 | +------------------------+ mysql> SELECT JSON_VALID('hello'), JSON_VALID('"hello"'); +---------------------+-----------------------+ | JSON_VALID('hello') | JSON_VALID('"hello"') | +---------------------+-----------------------+ | 0 | 1 | +---------------------+-----------------------+
-
1、 concat() 2、concat_ws() 3、group_concat()Mysql 有函数可以对字段进行拼接concat()将多个字段使用空字符串拼接为一个字段mysql> select concat(id, type) from mm_content limit 10; +------------------+ | concat(id, type) | +------------------+ | 100818image | | 100824image | | 100825video | | 100826video | | 100827video | | 100828video | | 100829video | | 100830video | | 100831video | | 100832video | +------------------+ 10 rows in set (0.00 sec) 不过如果有字段值为 NULL,则结果为 NULL。mysql> select concat(id, type, tags) from mm_content limit 10; +------------------------+ | concat(id, type, tags) | +------------------------+ | NULL | | NULL | | NULL | | NULL | | NULL | | NULL | | NULL | | NULL | | NULL | | NULL | +------------------------+ 10 rows in set (0.00 sec)concat_ws()上面这种方式如果想要使用分隔符分割,就需要每个字段中间插一个字符串,非常麻烦。concat_ws() 可以一次性的解决分隔符的问题,并且不会因为某个值为 NUll,而全部为 NUll。mysql> select concat_ws(' ', id, type, tags) from mm_content limit 10; +--------------------------------+ | concat_ws(' ', id, type, tags) | +--------------------------------+ | 100818 image | | 100824 image | | 100825 video | | 100826 video | | 100827 video | | 100828 video | | 100829 video | | 100830 video | | 100831 video | | 100832 video | +--------------------------------+ 10 rows in set (0.00 sec)group_concat()最后一个厉害了,正常情况下一个语句写成这样一定会报错的。mysql> select id from test_user group by age; ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test_user.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by但是 group_concat() 可以将分组状态下的其他字段拼接成字符串查询出来mysql> select group_concat(name) from test_user group by age; +--------------------+ | group_concat(name) | +--------------------+ | wen,ning | | wxnacy,win | +--------------------+ 2 rows in set (0.00 sec)默认使用逗号分隔,我们也可以指定分隔符mysql> select group_concat(name separator ' ') from test_user group by age; +----------------------------------+ | group_concat(name separator ' ') | +----------------------------------+ | wen ning | | wxnacy win | +----------------------------------+ 2 rows in set (0.00 sec)将字符串按照某个顺序排列mysql> select group_concat(name order by id desc separator ' ') from test_user group by age; +---------------------------------------------------+ | group_concat(name order by id desc separator ' ') | +---------------------------------------------------+ | ning wen | | win wxnacy | +---------------------------------------------------+ 2 rows in set (0.00 sec)如果想要拼接多个字段,默认是用空字符串进行拼接的,我们可以利用 concat_ws() 方法嵌套一层mysql> select group_concat(concat_ws(',', id, name) separator ' ') from test_user group by age; +------------------------------------------------------+ | group_concat(concat_ws(',', id, name) separator ' ') | +------------------------------------------------------+ | 1,wen 2,ning | | 3,wxnacy 4,win | +------------------------------------------------------+ 2 rows in set (0.00 sec)
-
MySql索引索引优点 1.可以通过建立唯一索引或者主键索引,保证数据的唯一性. 2.提高检索的数据性能 3.在表连接的连接条件 可以加速表与表直接的相连 4.建立索引,在查询中使用索引 可以提高性能索引缺点 1.在创建索引和维护索引 会耗费时间,随着数据量的增加而增加 2.索引文件会占用物理空间,除了数据表需要占用物理空间之外,每一个索引还会占用一定的物理空间 3.当对表的数据进行 INSERT,UPDATE,DELETE 的时候,索引也要动态的维护,这样就会降低数据的维护速度,(建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合索引,索引文件的会膨胀很快)。使用索引需要注意的地方 1.在经常需要搜索的列上,可以加快索引的速度 2.主键列上可以确保列的唯一性 3.在表与表的而连接条件上加上索引,可以加快连接查询的速度 4.在经常需要排序(order by),分组(group by)和的distinct 列上加索引 可以加快排序查询的时间, (单独order by 用不了索引,索引考虑加where 或加limit) 5.在一些where 之后的 < <= > >= BETWEEN IN 以及某个情况下的like 建立字段的索引(B-TREE) 6.like语句的 如果你对nickname字段建立了一个索引.当查询的时候的语句是 nickname lick '%ABC%' 那么这个索引讲不会起到作用.而nickname lick 'ABC%' 那么将可以用到索引 7.索引不会包含NULL列,如果列中包含NULL值都将不会被包含在索引中,复合索引中如果有一列含有NULL值那么这个组合索引都将失效,一般需要给默认值0或者 ' '字符串 8.使用短索引,如果你的一个字段是Char(32)或者int(32),在创建索引的时候指定前缀长度 比如前10个字符 (前提是多数值是唯一的..)那么短索引可以提高查询速度,并且可以减少磁盘的空间,也可以减少I/0操作. 9.不要在列上进行运算,这样会使得mysql索引失效,也会进行全表扫描 10.选择越小的数据类型越好,因为通常越小的数据类型通常在磁盘,内存,cpu,缓存中 占用的空间很少,处理起来更快什么情况下不创建索引 1.查询中很少使用到的列 不应该创建索引,如果建立了索引然而还会降低mysql的性能和增大了空间需求. 2.很少数据的列也不应该建立索引,比如 一个性别字段 0或者1,在查询中,结果集的数据占了表中数据行的比例比较大,mysql需要扫描的行数很多,增加索引,并不能提高效率 3.定义为text和image和bit数据类型的列不应该增加索引, 4.当表的修改(UPDATE,INSERT,DELETE)操作远远大于检索(SELECT)操作时不应该创建索引,这两个操作是互斥的关系
-
MySQL 获取系统当前时间MySQL 中 CURTIME() 和 CURRENT_TIME() 函数的作用相同,将当前时间以“HH:MM:SS”或“HHMMSS”格式返回,具体格式根据函数用在字符串或数字语境中而定。【实例】使用时间函数 CURTIME 和 CURRENT_TIME 获取系统当前时间,输入的 SQL 语句和执行结果如下所示。mysql> SELECT CURTIME(),CURRENT_TIME(),CURRENT_TIME()+0; +-----------+----------------+------------------+ | CURTIME() | CURRENT_TIME() | CURRENT_TIME()+0 | +-----------+----------------+------------------+ | 19:39:51 | 19:39:51 | 193951 | +-----------+----------------+------------------+ 1 row in set (0.04 sec)由运行结果可以看出,两个函数返回的结果相同,都返回了当前的系统时间。CURRENT_TIME()+0 是将当前日期值转换为数值型的。获取系统当前日期MySQL 中 CURDATE() 和 CURRENT_DATE() 函数的作用相同,将当前日期按照“YYYY-MM-DD”或“YYYYMMDD”格式的值返回,具体格式根据函数用在字符串或数字语境中而定。【实例】使用日期函数 CURDATE 和 CURRENT_DATE 获取系统当前日期,输入的 SQL 语句和执行结果如下所示。mysql> SELECT CURDATE(),CURRENT_DATE(),CURRENT_DATE()+0; +------------+----------------+------------------+ | CURDATE() | CURRENT_DATE() | CURRENT_DATE()+0 | +------------+----------------+------------------+ | 2017-04-01 | 2017-04-01 | 20170401 | +------------+----------------+------------------+ 1 row in set (0.03 sec)由运行结果可以看到,两个函数的作用相同,返回了相同的系统当前日期,“CURDATE()+0”将当前日期值转换为数值型的。
-
简单介绍几个常见的概念性问题我字段类型是not null,为什么我可以插入空值为毛not null的效率比null高判断字段不为空的时候,到底要 select * from table where column <> '' 还是要用 select * from table wherecolumn is not null 呢。空值是不占用空间的mysql中的NULL其实是占用空间的,下面是来自于MYSQL官方的解释: “NULL columns require additional space in the row to record whether their values are NULL. For MyISAM tables, each NULL column takes one bit extra, rounded up to the nearest byte.”比方说:你有一个杯子,空值代表杯子是真空的,NULL代表杯子中装满了空气,虽然杯子看起来都是空的,但是区别是很大的。测试例子:CREATE TABLE `test` ( `col1` VARCHAR( 10 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , `col2` VARCHAR( 10 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL ) ENGINE = MYISAM ;插入数据INSERT INTO `test` VALUES (null,1);发生错误#1048 - Column 'col1' cannot be null继续插入INSERT INTO `test` VALUES ('',1);插入成功NOT NULL 的字段是不能插入“NULL”的,只能插入“空值”,上面的问题1也就有答案了。对于问题2,上面我们已经说过了,NULL 其实并不是空值,而是要占用空间,所以mysql在进行比较的时候,NULL 会参与字段比较,所以对效率有一部分影响。而且B树索引时不会存储NULL值的,所以如果索引的字段可以为NULL,索引的效率会下降很多。添加数据:INSERT INTO `test` VALUES ('', NULL); INSERT INTO `test` VALUES ('1', '2');表中数据:现在根据需求,我要统计test表中col1不为空的所有数据,我是该用“<> ''” 还是 “IS NOT NULL” 呢,让我们来看一下结果的区别。SELECT * FROM `test` WHERE col1 IS NOT NULLSELECT * FROM `test` WHERE col1 IS NOT NULL可以看到,结果迥然不同,所以我们一定要根据业务需求,搞清楚到底是要用那种搜索条件。MYSQL建议列属性尽量为NOT NULL长度验证:注意空值的''之间是没有空格的。mysql> select length(''),length(null),length(' '); +------------+--------------+--------------+ | length('') | length(null) | length(' ') | +------------+--------------+--------------+ | 0 | NULL | 2 | +------------+--------------+--------------+注意:在进行count()统计某列的记录数的时候,如果采用的NULL值,系统会自动忽略掉,但是空值是会进行统计到其中的。判断NULL 用IS NULL 或者 IS NOT NULL, SQL语句函数中可以使用ifnull()函数来进行处理,判断空字符用=''或者 <>''来进行处理对于MySQL特殊的注意事项,对于timestamp数据类型,如果往这个数据类型插入的列插入NULL值,则出现的值是当前系统时间。插入空值,则会出现 0000-00-00 00:00:00对于空值的判断到底是使用is null 还是='' 要根据实际业务来进行区分。
-
MySQL 作为目前最为活跃热门的开源数据库之一,具有低成本和简易操作的特点。在炙手可热的 BAT(百度、阿里巴巴、腾讯)中,都大量使用了 MySQL。显然,对于想在互联网行业大展手脚的数据库工程师和 DBA 们,熟练 MySQL 无疑是一块很好的敲门砖。每个人的情况不同,自称小白的人基本有以下 3 类:1)求职储备(无工作经验)没有相关经验,还没有走上工作岗位,只是对 MySQL 感兴趣或者好奇2)DBA萌新(较少工作经验)刚入行的新手,或者有少量经验的 DBA 新人,经常会发现实际工作和网上说的不一样3)工作中会用到(有工作经验)可能是开发类的同学,有一定工作经验,工作中要用到 MySQL 数据库,只是简单用,想深入学习一下对于 MySQL 的学习周期和难度,大家是很关心的。下面我们用比较成熟的商业数据库 Oracle 作为参考,来对比学习 MySQL 的一些特点。数据库名称OracleMySQL数据库类型商业闭源开源功能完善情况非常齐全比较齐全学习周期长较短学习难度(入门)难容易学习难度(深入)难更难Oracle到MySQL\相对容易MySQL到Oracle难\深度进阶内核、调试源码定制、改造从技术栈上来说,MySQL 的入门周期相对要短,学习难度较容易。但是如果要深入了解使用,因为其开源和社区的原因,发展空间更大,相对也就更难。另外,MySQL DBA 的“钱途”从市面需求来说也要好一些。从我的理解中,MySQL 主要有 3 个知识层面,即运维管理,架构优化和运维开发。1)运维管理运维管理主要就是基础运维的工作(安装部署,备份恢复,权限管理之类的工作)和一些变更类管理和规范操作(在线变更,数据库复制,SQL 规范等工作),这部分工作上手较快。2)架构优化架构和优化涉及的工作面比较宽,而且技术要求有一定的深度,主要分为 SQL 查询优化,事务和锁,MySQL 集群和高可用技术,分布式数据库架构等。这部分工作中对于很多开发同学来说,要注重于查询优化。而对于从初级走向中高级的 DBA 来说,则要更注重于相关的锁机制、集群和高可用相关技术。3)运维开发运维开发的工作不是简单的数据库自动化运维,而是分为应用层和内核。我们常说的运维开发是偏向于应用层的,比如数据库管理工具等。而内核层需要掌握源码开发能力,比如开发数据库中间件,SQL 审核工具等。MySQL 主要从事以下 3 方面工作。1)技术支持工程师。MySQL 只是该工作技能之一。掌握 MySQL 安装,维护和基本操作就可以。基本月薪 6K~10K。2)系统集成工程师。MySQL 只是该工作技能之一。掌握 MySQL 安装,维护和基本操作就可以。基本月薪 6K~10K。3)数据库工程师。这个就分很多种了,主要看 MySQL 的掌握程度。一般的是 MySQL 数据库管理员。基本月薪 10K~15K。高大上的有数据分析工程师,数据库开发工程师,数据库建模工程师,数据库挖掘工程师等,这类需要掌握 Oracle 数据库。基本月薪 15K~28K。所以学习任何一门技术都得认真,脚踏实地,未来很美好,加油,代码人!!!
-
MySQL设置日期自增后,自增的时间不是北京时间,有什么方法可以修改为北京时间吗
-
DML(Data Manipulation Language)数据操作语言,是指对数据库进行增删改的操作指令,主要有INSERT、UPDATE、DELETE三种,代表插入、更新与删除,这是学习MySQL必要掌握的基本知识。方语法中 [] 中内容可以省略。 INSERT操作 语法格式如下: insert into t_name[(column_name1,columnname_2,...)] values (val1,val2); 或者 insert into t_name set column_name1 = val1,column_name2 = val2;1、字段名称和值需要保证数量一直,类型一直,位置一 一对应,否则可能导致异常。2、not null的字段需要保证有插入的值,否则会报非空的异常信息。允许null的字段如果不想输入数据,字段和值都不出现,或者value用null代替。3、数值类型,值不需要用单引号括起来,其他的如字符型或日期类型,值需要用单引号括起来;4、如果表名后面的column_name 省略不写,则代表覆盖该表的所有字段。值的顺序和表中字段顺序须保持一致。5、上述第二种语法的写法更繁琐,现在比较少使用。测试mysql> desc `user1`; +---------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | name | varchar(20) | NO | | NULL | | | age | int(11) | NO | | 0 | | | address | varchar(255) | YES | | NULL | | +---------+--------------+------+-----+---------+----------------+ 4 rows in set mysql> insert into `user1`(name,age,address) values('brand',20,'fuzhou'); Query OK, 1 row affected mysql> insert into `user1`(age,address) values(20,'fuzhou'); 1364 - Field 'name' doesn't have a default value mysql> insert into `user1` values('sol',21,'xiamen'); 1136 - Column count doesn't match value count at row 1 mysql> insert into `user1` values(null,'sol',21,'xiamen'); Query OK, 1 row affected mysql> select * from `user1`; +----+-------+-----+---------+ | id | name | age | address | +----+-------+-----+---------+ | 3 | brand | 20 | fuzhou | | 4 | sol | 21 | xiamen | +----+-------+-----+---------+ 2 rows in set批量插入语法格式如下: insert into t_name [(column_name1,column_name2)] values (val1_1,val1_2),(val2_1,val2_2)...); 或者 insert into t_name [(column_name1,column_name2)] select o_name1,o_name2 from o_t_name [where condition];1、上述第一个语法,values 后面的值个数需要同等配对 column的数量,可以设置多个,逗号隔开,提高数据插入效率。2、第二个语法,select查询的字段和插入数据的字段数量、顺序、类型需要一致。 insert的字段可以省略,代表插入t_name表所有字段。条件可选。测试如下:mysql> insert into `user1`(name,age,address) values('brand',20,'fuzhou'),('sol',21,'xiamen'); Query OK, 2 rows affected Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from `user1`; +----+-------+-----+---------+ | id | name | age | address | +----+-------+-----+---------+ | 5 | brand | 20 | fuzhou | | 6 | sol | 21 | xiamen | +----+-------+-----+---------+ 2 rows in setmysql> desc `user2`; +---------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+----------------+ | id | bigint(20) | NO | PRI | NULL | auto_increment | | name | varchar(20) | NO | | NULL | | | age | int(11) | NO | | 0 | | | address | varchar(255) | YES | | NULL | | | sex | int(11) | NO | | 1 | | +---------+--------------+------+-----+---------+----------------+ 5 rows in set mysql> insert into `user2` (name,age,address,sex) select name,age,address,null from `user1`; Query OK, 2 rows affected Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from `user2`; +----+-------+-----+---------+------+ | id | name | age | address | sex | +----+-------+-----+---------+------+ | 7 | brand | 20 | fuzhou | 1 | | 8 | sol | 21 | xiamen | 1 | +----+-------+-----+---------+------+ 2 rows in setDELETE操作delete方式删除语法格式如下:delete [alias] from t_name [[as] alias] [where condition];1、跟上面一样,alias代表别名,没有别名情况下,表名就是别名2、如果表设置了别名,则delete后面必须跟上别名,否则数据库会报异常。测试代码:mysql> select * from `user2`; +----+------+-----+---------+------+ | id | name | age | address | sex | +----+------+-----+---------+------+ | 7 | hero | 23 | fuzhou | 1 | | 8 | sol | 21 | xiamen | NULL | +----+------+-----+---------+------+ 2 rows in set mysql> delete from `user2` as alias where sex=1; 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'as alias where sex=1' at line 1 mysql> delete alias from `user2` as alias where sex=1; Query OK, 1 row affected mysql> select * from `user2`; +----+------+-----+---------+------+ | id | name | age | address | sex | +----+------+-----+---------+------+ | 8 | sol | 21 | xiamen | NULL | +----+------+-----+---------+------+ 1 row in set3、如果删除表中所有的数据,则后面不带上where条件即可,不过要谨慎使用哟。mysql> select * from `user2`; +----+-------+-----+----------+-----+ | id | name | age | address | sex | +----+-------+-----+----------+-----+ | 8 | sol | 21 | xiamen | 0 | | 10 | brand | 21 | fuzhou | 1 | | 11 | helen | 20 | quanzhou | 0 | +----+-------+-----+----------+-----+ 3 rows in set mysql> delete from `user2`; Query OK, 3 rows affected mysql> select * from `user2`; Empty settruncate方式删除测试代码如下:truncate t_name;mysql> select * from `user2`; +----+-------+-----+----------+-----+ | id | name | age | address | sex | +----+-------+-----+----------+-----+ | 12 | brand | 21 | fuzhou | 1 | | 13 | helen | 20 | quanzhou | 0 | | 14 | sol | 21 | xiamen | 0 | +----+-------+-----+----------+-----+ 3 rows in set mysql> truncate `user2`; Query OK, 0 rows affected mysql> select * from `user2`; Empty set看起来跟delete很像,但是重新插入数据会发现,他的自增主键会重新从1开始,但是delete的是直接在原来的所以自增值之后往上加。看下面id字段。mysql> insert into `user2` (name,age,address,sex) values('brand',21,'fuzhou',1),('helen',20,'quanzhou',0),('sol',21,'xiamen',0); Query OK, 3 rows affected Records: 3 Duplicates: 0 Warnings: 0 mysql> select * from `user2`; +----+-------+-----+----------+-----+ | id | name | age | address | sex | +----+-------+-----+----------+-----+ | 1 | brand | 21 | fuzhou | 1 | | 2 | helen | 20 | quanzhou | 0 | | 3 | sol | 21 | xiamen | 0 | +----+-------+-----+----------+-----+ 3 rows in settruncate和delete的比较1、truncate 指的是清空表的数据、释放表的空间,但不删除表的架构定义(表结构)。因为不包含Where条件,所以不是删除具体行,而是将整个表清空了。2、而delete 语句是删除表中的数据行,可以在后面带上条件控制删除的维度、范围,它每次从表中删除一行,会同时将该行的删除操作作为事务保存在日志中,用于进行可能的回滚操作。3、truncate 和 delete 一样的地方是:只是删除数据,涉及到的表结构及其列、约束、索引等均不会变。4、如果被外键 foreign key 约束,不能使用truncate ,只能使用不带where子句的delete语句。5、truncate 操作会记录在日志中,delete操作会放到 rollback segement 中,执行时要等事务被commit才会生效;所以delete 会触发删除触发器(如果有的话),truncate 不会。6、如果像上面我们测试的那样,包含自增字段,truncate方式清空之后,自增列的值会被初始化从1开始。delete方式要分情况判断(如果数据全部delete,数据库未被重启,则按照之前max+1;数据库重启了,则一样会重新开始计算自增列的初始值)。7、还有drop,drop语句会删除表包括 结构、数据、依赖该表的约束(constrain),触发器(trigger)索引(index)等。
上滑加载中
推荐直播
-
华为云码道Agent集成与鸿蒙实战2026/08/11 周二 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;彭江敏-华为云鸿蒙端云一体化开发专家
本次直播带你解读华为云码道7月份产品新特性、新功能。更有专家演示码道Agent Space × 钉钉机器集成实战,从0到1打通消息通道;码道鸿蒙端云一体化实战,快速搭建员工签到系统。
回顾中 -
华为云开发者AI素养直播课·第五期2026/09/04 周五 16:00-18:00
林华鼎-华为云AI开发者运营负责人;蒋春阳-华为云AI开发者案例开发专家
本期直播内容: AI工具体验营 · 第5-8课连讲。Agent-Team 多智能体协作完成毕业设计实践
回顾中 -
华为云开发者AI素养ClassRoom·第六期2026/09/08 周二 19:00-20:00
樊渊-2026华为软件挑战赛冠军
高手来了:看软挑高手解析二维排样问题—从工业难题到算法突破
回顾中
热门标签