-
为实现数据库中表规范化设计的目的,有时候需要对之前已经创建的表进行结构修改或者调整。在 MySQL 中可以使用 ALTER TABLE 语句来改变原有表的结构,例如增加或删减列、创建或取消索引、更改原有列类型、重新命名列或表等。基本语法修改表指的是修改数据库中已经存在的数据表的结构。MySQL 使用 ALTER TABLE 语句修改表。常用的修改表的操作有修改表名、修改字段数据类型或字段名、增加和删除字段、修改字段的排列位置、更改表的存储引擎、删除表的外键约束等。常用的语法格式如下:ALTER TABLE <表名> [修改选项]修改选项的语法格式如下:{ ADD COLUMN <列名> <类型>| CHANGE COLUMN <旧列名> <新列名> <新列类型>| ALTER COLUMN <列名> { SET DEFAULT <默认值> | DROP DEFAULT }| MODIFY COLUMN <列名> <类型>| DROP COLUMN <列名>| RENAME TO <新表名> }添加字段随着业务的变化,可能需要在已经存在的表中添加新的字段,一个完整的字段包括字段名、数据类型、完整性约束。添加字段的语法格式如下:ALTER TABLE <表名> ADD <新字段名> <数据类型> [约束条件] [FIRST|AFTER 已存在的字段名];新字段名为需要添加的字段的名称;FIRST 为可选参数,其作用是将新添加的字段设置为表的第一个字段;AFTER 为可选参数,其作用是将新添加的字段添加到指定的已存在的字段名的后面。【实例 1】使用 ALTER TABLE 修改表 tb_emp1 的结构,在表的第一列添加一个 int 类型的字段 col1,输入的 SQL 语句和运行结果如下所示。mysql> ALTER TABLE tb_emp1 -> ADD COLUMN col1 INT FIRST; Query OK, 0 rows affected (0.94 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> DESC tb_emp1; +--------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+-------+ | col1 | int(11) | YES | | NULL | | | id | int(11) | YES | | NULL | | | name | varchar(25) | YES | | NULL | | | deptId | int(11) | YES | | NULL | | | salary | float | YES | | NULL | | +--------+-------------+------+-----+---------+-------+ 5 rows in set (0.00 sec)提示:“FIRST 或 AFTER 已存在的字段名”用于指定新增字段在表中的位置,如果 SQL 语句中没有这两个参数,则默认将新添加的字段设置为数据表的最后列。【实例 2】使用 ALTER TABLE 修改表 tb_emp1 的结构,在一列 name 后添加一个 int 类型的字段 col2,输入的 SQL 语句和运行结果如下所示。mysql> ALTER TABLE tb_emp1 -> ADD COLUMN col2 INT AFTER name; Query OK, 0 rows affected (0.50 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> DESC tb_emp1; +--------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+-------+ | col1 | int(11) | YES | | NULL | | | id | int(11) | YES | | NULL | | | name | varchar(25) | YES | | NULL | | | col2 | int(11) | YES | | NULL | | | deptId | int(11) | YES | | NULL | | | salary | float | YES | | NULL | | +--------+-------------+------+-----+---------+-------+ 6 rows in set (0.00 sec)可以看到,表 tb_emp1 中增加了一个名称为 col2 的字段,其位置在指定的 name 字段后面,添加字段成功。修改字段数据类型修改字段的数据类型就是把字段的数据类型转换成另一种数据类型。在 MySQL 中修改字段数据类型的语法规则如下:ALTER TABLE <表名> MODIFY <字段名> <数据类型>其中,表名指要修改数据类型的字段所在表的名称,字段名指需要修改的字段,数据类型指修改后字段的新数据类型。【实例 3】使用 ALTER TABLE 修改表 tb_emp1 的结构,将 name 字段的数据类型由 VARCHAR(22) 修改成 VARCHAR(30),输入的 SQL 语句和运行结果如下所示。mysql> ALTER TABLE tb_emp1 -> MODIFY name VARCHAR(30); Query OK, 0 rows affected (0.15 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> DESC tb_emp1; +--------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+-------+ | col1 | int(11) | YES | | NULL | | | id | int(11) | YES | | NULL | | | name | varchar(30) | YES | | NULL | | | col2 | int(11) | YES | | NULL | | | deptId | int(11) | YES | | NULL | | | salary | float | YES | | NULL | | +--------+-------------+------+-----+---------+-------+ 6 rows in set (0.00 sec)语句执行后,发现表 tb_emp1 中 name 字段的数据类型已经修改成 VARCHAR(30),修改成功。删除字段删除字段是将数据表中的某个字段从表中移除,语法格式如下:ALTER TABLE <表名> DROP <字段名>;其中,字段名指需要从表中删除的字段的名称。【实例 4】使用 ALTER TABLE 修改表 tb_emp1 的结构,删除 col2 字段,输入的 SQL 语句和运行结果如下所示。mysql> ALTER TABLE tb_emp1 -> DROP col2; Query OK, 0 rows affected (0.53 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> DESC tb_emp1; +--------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+-------+ | col1 | int(11) | YES | | NULL | | | id | int(11) | YES | | NULL | | | name | varchar(30) | YES | | NULL | | | deptId | int(11) | YES | | NULL | | | salary | float | YES | | NULL | | +--------+-------------+------+-----+---------+-------+ 5 rows in set (0.00 sec)修改字段名称MySQL 中修改表字段名的语法规则如下:ALTER TABLE <表名> CHANGE <旧字段名> <新字段名> <新数据类型>;其中,旧字段名指修改前的字段名;新字段名指修改后的字段名;新数据类型指修改后的数据类型,如果不需要修改字段的数据类型,可以将新数据类型设置成与原来一样,但数据类型不能为空。【实例 5】使用 ALTER TABLE 修改表 tb_emp1 的结构,将 col1 字段名称改为 col3,同时将数据类型变为 CHAR(30),输入的 SQL 语句和运行结果如下所示。mysql> ALTER TABLE tb_emp1 -> CHANGE col1 col3 CHAR(30); Query OK, 0 rows affected (0.76 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> DESC tb_emp1; +--------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+-------+ | col3 | char(30) | YES | | NULL | | | id | int(11) | YES | | NULL | | | name | varchar(30) | YES | | NULL | | | deptId | int(11) | YES | | NULL | | | salary | float | YES | | NULL | | +--------+-------------+------+-----+---------+-------+ 5 rows in set (0.01 sec)CHANGE 也可以只修改数据类型,实现和 MODIFY 同样的效果,方法是将 SQL 语句中的“新字段名”和“旧字段名”设置为相同的名称,只改变“数据类型”。提示:由于不同类型的数据在机器中的存储方式及长度并不相同,修改数据类型可能会影响数据表中已有的数据记录,因此,当数据表中已经有数据时,不要轻易修改数据类型。修改表名MySQL 通过 ALTER TABLE 语句来实现表名的修改,语法规则如下:ALTER TABLE <旧表名> RENAME [TO] <新表名>;其中,TO 为可选参数,使用与否均不影响结果。【实例 6】使用 ALTER TABLE 将数据表 tb_emp1 改名为 tb_emp2,输入的 SQL 语句和运行结果如下所示。mysql> ALTER TABLE tb_emp1 -> RENAME TO tb_emp2; mysql> SHOW TABLES; +--------------------+ | Tables_in_test_db | +--------------------+ | tb_emp2 | +--------------------+ 1 rows in set (0.00 sec)提示:用户可以在修改表名称时使用 DESC 命令查看修改后两个表的结构,修改表名并不修改表的结构,因此修改名称后的表和修改名称前的表的结构是相同的。
-
在做开发测试环境和生产误操作导致数据库误删除/更新,对DBA而言,回滚数据着实是一件头疼的事情,凡涉及到恢复线上数据必然对应用带来一定的影响。较多的情况是开发误操作delete数据,update多数行,根据之前的操作经验,下面介绍常用的恢复方法。1 .利用备份恢复使用这种方式的前提必须有最近的备份集或者知道出现误操作起始的binlog 位点或者GTID,利用备份集恢复到中间的机器上,然后利用MySQL的slave 特性START SLAVE [SQL_THREAD] UNTIL MASTER_LOG_FILE = 'log_name', MASTER_LOG_POS = log_pos;until_option:UNTIL { {SQL_BEFORE_GTIDS | SQL_AFTER_GTIDS} = gtid_set | MASTER_LOG_FILE = 'log_name', MASTER_LOG_POS = log_pos | RELAY_LOG_FILE = 'log_name', RELAY_LOG_POS = log_pos | SQL_AFTER_MTS_GAPS }恢复出到一个临时的实例,将误删除,更新的数据 dump 出来并恢复到老的实例里面。恢复数据期间的受影响的表最好不可写,否则将难以达到最想要的结果。例如 a=2 ,被误更新为 a=4,恢复的期间有被更新为a=7 ,结果恢复后又恢复为a=2 。 此种恢复方式 不适合恢复大量数据库,且需要临时实例。2.2 利用开源工具binlog2sql 恢复binlog2sql 是大众点评公司的DBA 开发的一款基于通过解析binlog将delete 恢复为insert,update 的值 set 字段和where条件做对调的原理来恢复数据的。 使用限制 MySQL的binlog format 必须是row 安装git clone https://github.com/danfengcao/binlog2sql.git && cd binlog2sql pip install -r requirements.txt用法usage: binlog2sql.py [-h HOST] [-u USER] [-p PASSWORD] [-P PORT] [--start-file STARTFILE] [--start-position STARTPOS] [--stop-file ENDFILE] [--stop-position ENDPOS] [--start-datetime STARTTIME] [--stop-datetime STOPTIME] [--stop-never] [-d [DATABASES [DATABASES ...]]] [-t [TABLES [TABLES ...]]] [-K] [-B] [--help]例子create table flashback( id int(11) not null auto_increment primary key , stat int(11) not null default 1 ) engine=innodb default charset=utf8; insert into flashback(stat) values (2),(3),(4),(7),(9),(22),(42),(33),(66),(88)误操作update flashback set stat=15恢复数据的步骤1.获取误操作的dml所在的binlog,不过一般开发可不知道具体binlog,他们只知道什么时间误操作了,binlog2sql支持按照时间范围恢复。mysql> show master logs; +------------------+-----------+ | Log_name | File_size | +------------------+-----------+ | mysql-bin.000009 | 177 | | mysql-bin.000010 | 464 | | mysql-bin.000011 | 8209 | +------------------+-----------+ 3 rows in set (0.00 sec)例子中binlog为mysql-bin.0000112.利用binlog2sql 恢复数据,先解析binlog获取 update 语句的起始位点,本例中 start 5087 end 5428,执行命令python binlog2sql.py -h127.0.0.1 -P3307 -udba -p'dbadmin' -dyang -tflashback --start-file='mysql-bin.000011'使用binlog2sql -B 参数得到恢复的sql将获取到的sql 执行到数据库,假如生产环境中真的发生了问题,一定要和开发沟通并且确认需要恢复的确切记录。mysql> select * from flashback; +----+------+ | id | stat | +----+------+ | 1 | 2 | | 2 | 3 | | 3 | 4 | | 4 | 7 | | 5 | 9 | | 6 | 22 | | 7 | 42 | | 8 | 33 | | 9 | 66 | | 10 | 88 | +----+------+ 10 rows in set (0.00 sec)binlog2sql的特点:mysql server必须开启,离线模式下不能解析 优点(对比mysqlbinlog) 。纯Python开发,安装与使用都很简单。自带flashback、no-primary-key解析模式,无需再装补丁。flashback模式下,更适合闪回实战。解析为标准SQL,方便理解、调试。代码容易改造,可以支持更多个性化解析.其实MySQL 还提供了一个参数 sql_safe_updates,该参数将禁止 不带where 条件的delete和update语句。具体用法和介绍还请参考MySQL官方介绍。
-
一些情况需要查看当前最新的事务 ID,方便做一些业务逻辑上的判断(例如利用事务 ID 变化以及前后时差,统计每次事务的响应时长等用途)。通常地,我们有两种方法可以查看当前的事务 ID:1、执行 SHOW ENGINE INNODB STATUS,查看事务相关信息Per second averages calculated from the last 15 seconds TRANSACTIONS Trx id counter 3359877657 -- 当前最大事务 ID Purge done for trx's n:o < 3359877468 undo n:o < 0 state: running History list length 324 LIST OF TRANSACTIONS FOR EACH SESSION: ---TRANSACTION 0, not started -- 该会话中执行 SHOW ENGINE INNODB STATUS,不会产生事务,所以事务 ID 为 0 MySQL thread id 4692367, OS thread handle 0x51103940, query id 677284426 xx.173ops.com 10.x.x.x yejr init SHOW /*!50000 ENGINE*/ INNODB STATUS ---TRANSACTION 3359877640, not started --非活跃事务,还未开始 mysql tables in use 1, locked 0 MySQL thread id 4678384, OS thread handle 0x41a57940, query id 677284427 xx.173ops.com 10.x.x.x yejr System lock select polinfo0_.Fid as Fid39_0_, ... ---TRANSACTION 3359877652, not started MySQL thread id 4678383, OS thread handle 0x50866940, query id 677284420 xx.173ops.com 10.x.x.x yejr cleaning up ---TRANSACTION 3359877635, ACTIVE 1358 sec, thread declared inside InnoDB 5000 --活跃长事务,运行了 1358 秒还未结束,要引起注意,可能会导致大量锁等待发生 mysql tables in use 1, locked 1 1 lock struct(s), heap size 376, 0 row lock(s), undo log entries 1 MySQL thread id 3120717, OS thread handle 0x529b4940, query id 677284351 xx.173ops.com 10.x.x.x yejr query end insert into t_live_room ...2、查看 INFORMATION_SCHEMA.INNODB_TRX、INNODB_LOCKS、INNODB_LOCK_WAITS 三个表,通过这些信息能快速发现哪些事务在阻塞其他事务先查询 INNODB_TRX 表,看看都有哪些事务mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX\G ************ 1. row ********** trx_id: 17778 -- 当前事务 ID trx_state: LOCK WAIT -- 处于锁等待状态,也就是等待其他会话释放锁资源 trx_started: 2015-03-04 10:40:26 trx_requested_lock_id: 17778:82:3:6 -- 欲请求的锁 trx_wait_started: 2015-03-04 10:40:26 trx_weight: 2 -- 大意是该锁影响了 2 行记录 trx_mysql_thread_id: 657 -- processlist 中的线程 ID trx_query: update trx_fee set fee=rand()*1000 where id= 4 trx_operation_state: starting index read trx_tables_in_use: 1 trx_tables_locked: 1 trx_lock_structs: 2 trx_lock_memory_bytes: 360 trx_rows_locked: 1 trx_rows_modified: 0 trx_concurrency_tickets: 0 trx_isolation_level: REPEATABLE READ trx_unique_checks: 1 trx_foreign_key_checks: 1 trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 10000 trx_is_read_only: 0 trx_autocommit_non_locking: 0 ****** 2. row ********* trx_id: 17773 trx_state: RUNNING trx_started: 2015-03-04 10:40:23 trx_requested_lock_id: NULL trx_wait_started: NULL trx_weight: 10 trx_mysql_thread_id: 656 trx_query: NULL trx_operation_state: NULL trx_tables_in_use: 0 trx_tables_locked: 0 trx_lock_structs: 2 trx_lock_memory_bytes: 360 trx_rows_locked: 9 trx_rows_modified: 8 trx_concurrency_tickets: 0 trx_isolation_level: REPEATABLE READ trx_unique_checks: 1 trx_foreign_key_checks: 1 trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 10000 trx_is_read_only: 0 trx_autocommit_non_locking: 0 再看 INNODB_LOCKS 表,看看都有什么锁mysql> select * from information_schema.INNODB_LOCKS\G *************************** 1. row *************************** lock_id: 17778:82:3:6 --当前锁 ID lock_trx_id: 17778 --该锁对应的事务 ID lock_mode: X -- 锁类型,排它锁 X lock_type: RECORD --锁范围,记录锁:record lock,其他锁范围:间隙锁:gap lock,或者 next-key lock(记录锁+间隙锁) lock_table: `test`.`trx_fee` lock_index: PRIMARY --加载在哪个索引上的锁 lock_space: 82 lock_page: 3 lock_rec: 6 lock_data: 4 *************************** 2. row *************************** lock_id: 17773:82:3:6 lock_trx_id: 17773 lock_mode: X lock_type: RECORD lock_table: `test`.`trx_fee` lock_index: PRIMARY lock_space: 82 lock_page: 3 lock_rec: 6 lock_data: 4最后看 INNODB_LOCK_WAITS 表,看看当前都有哪些锁等待mysql> select * from information_schema.INNODB_LOCK_WAITS\G *************************** 1. row *************************** requesting_trx_id: 17778 --请求锁的事务 ID(等待方) requested_lock_id: 17778:82:3:6 -- 请求锁 ID blocking_trx_id: 17773 -- 阻塞该锁的事务 ID(当前持有方,待释放) blocking_lock_id: 17773:82:3:6 -- 持有的锁 ID3、利用 percona 分支的特性,查看当前最新事务 ID,该特性从 5.6.11-60.3 版本开始引入,执行下面的 2 个命令即可查看mysqladmin ext | grep Innodb_max_trx_id 或者 mysql> show global status like 'Innodb_max_trx_id';最后,交代下问题的来源其实是这样的,有位朋友和我讨论问题,说在 java 连接池中,发现 2 个事务的事务 ID 是一样的,测试的 SQL 代码:begin;update trx set un=rand() where id=round(rand()*10)+1;select * from information_schema.INNODB_TRX; commit;select sleep(0.01);begin;update trx set un=rand() where id=round(rand()*10)+1;select * from information_schema.INNODB_TRX;commit;百看不如自己在自己的环境中尝试!
-
MySQL 中内连接是在交叉连接的结果集上返回满足条件的记录;而外连接先将连接的表分为基表和参考表,再以基表为依据返回满足和不满足条件的记录。外连接更加注重两张表之间的关系。按照连接表的顺序,可以分为左外连接和右外连接。左外连接又称为左连接,在 FROM 子句中使用关键字 LEFT OUTER JOIN 或者 LEFT JOIN,用于接收该关键字左表(基表)的所有行,并用这些行与该关键字右表(参考表)中的行进行匹配,即匹配左表中的每一行及右表中符合条件的行。在左外连接的结果集中,除了匹配的行之外,还包括左表中有但在右表中不匹配的行,对于这样的行,从右表中选择的列的值被设置为 NULL,即左外连接的结果集中的 NULL 值表示右表中没有找到与左表相符的记录。【实例 1】在 tb_students_info 表和 tb_departments 表中查询所有学生,包括没有学院的学生,输入的 SQL 语句和执行结果如下所示。mysql> SELECT name,dept_name -> FROM tb_students_info s -> LEFT OUTER JOIN tb_departments d -> ON s.dept_id = d.dept_id; +--------+-----------+ | name | dept_name | +--------+-----------+ | Dany | Computer | | Jane | Computer | | Jim | Computer | | Henry | Math | | John | Math | | Green | Chinese | | Thomas | Chinese | | Susan | Economy | | Tom | Economy | | Lily | NULL | +--------+-----------+ 10 rows in set (0.03 sec)结果显示了 10 条记录,name 为 Lily 的学生目前没有学院,因为对应的 tb_departments 表中并没有该学生的学院信息,所以该条记录只取出了 tb_students_info 表中相应的值,而从 tb_departments 表中取出的值为 NULL。右外连接又称为右连接,在 FROM 子句中使用 RIGHT OUTER JOIN 或者 RIGHT JOIN。与左外连接相反,右外连接以右表为基表,连接方法和左外连接相同。在右外连接的结果集中,除了匹配的行外,还包括右表中有但在左表中不匹配的行,对于这样的行,从左表中选择的值被设置为 NULL。【实例 2】在 tb_students_info 表和 tb_departments 表中查询所有学院,包括没有学生的学院,输入的 SQL 语句和执行结果如下所示。mysql> SELECT name,dept_name -> FROM tb_students_info s -> RIGHT OUTER JOIN tb_departments d -> ON s.dept_id = d.dept_id; +--------+-----------+ | name | dept_name | +--------+-----------+ | Dany | Computer | | Green | Chinese | | Henry | Math | | Jane | Computer | | Jim | Computer | | John | Math | | Susan | Economy | | Thomas | Chinese | | Tom | Economy | | NULL | History | +--------+-----------+ 10 rows in set (0.00 sec)可以看到,结果只显示了 10 条记录,名称为 History 的学院目前没有学生,对应的 tb_students_info 表中并没有该学院的信息,所以该条记录只取出了 tb_departments 表中相应的值,而从 tb_students_info 表中取出的值为 NULL。
-
在使用 MySQL SELECT语句时,可以使用 WHERE 子句来指定查询条件,从 FROM 子句的中间结果中选取适当的数据行,达到数据过滤的效果。语法格式如下:WHERE <查询条件> {<判定运算1>,<判定运算2>,…}其中,判定运算其结果取值为 TRUE、FALSE 和 UNKNOWN。判定运算的语法分类如下:<表达式1>{=|<|<=|>|>=|<=>|<>|!=}<表达式2><表达式1>[NOT]LIKE<表达式2><表达式1>[NOT][REGEXP|RLIKE]<表达式2><表达式1>[NOT]BETWEEN<表达式2>AND<表达式3><表达式1>IS[NOT]NULL单一条件的查询语句【实例 1】在表 tb_students_info 中查询身高为 170cm 的学生的姓名,输入的 SQL 语句和行结果如下所示。mysql> use test_db Database changed mysql> SELECT name,height -> FROM tb_students_info -> WHERE height=170; +-------+--------+ | name | height | +-------+--------+ | Susan | 170 | +-------+--------+ 1 row in set (0.17 sec)该语句采用了简单的相等过滤,查询一个指定列 height 的具体值 170。【实例 2】查询年龄小于 22 的学生的姓名,输入的 SQL 语句和执行结果如下所示。mysql> SELECT name,age -> FROM tb_students_info -> WHERE age<22; +------+------+ | name | age | +------+------+ | John | 21 | +------+------+ 1 row in set (0.05 sec)可以看到,查询结果中所有记录的 age 字段的值均小于 22 岁,而大于或等于 22 岁的记录没有被返回。多条件的查询语句使用 SELECT 查询时,可以增加查询的限制条件,这样可以使查询的结果更加精确。MySQL 在 WHERE 子句中使用 AND 操作符限定只有满足所有查询条件的记录才会被返回。可以使用 AND 连接两个甚至多个查询条件,多个条件表达式之间用 AND 分开。【实例 3】在 tb_students_info 表中查询 age 大于 21,并且 height 大于等于 175 的学生的信息,输入的 SQL 语句和执行结果如下所示。mysql> SELECT * FROM tb_students_info -> WHERE age>21 AND height>=175; +----+--------+---------+------+------+--------+------------+ | id | name | dept_id | age | sex | height | login_date | +----+--------+---------+------+------+--------+------------+ | 3 | Henry | 2 | 23 | M | 185 | 2015-05-31 | | 5 | Jim | 1 | 24 | M | 175 | 2016-01-15 | | 9 | Thomas | 3 | 22 | M | 178 | 2016-06-07 | +----+--------+---------+------+------+--------+------------+ 3 rows in set (0.06 sec)注意:上例的 WHERE 子句中只包含一个 AND 语句,把两个过滤条件组合在一起,实际上可以添加多个 AND 过滤条件,增加条件的同时增加一个 AND 关键字。使用 LIKE 的模糊查询字符串匹配的语法格式如下:<表达式1> [NOT] LIKE <表达式2>字符串匹配是一种模式匹配,使用运算符 LIKE 设置过滤条件,过滤条件使用通配符进行匹配运算,而不是判断是否相等进行比较。相互间进行匹配运算的对象可以是 CHAR、VARCHAR、TEXT、DATETIME 等数据类型。运算返回的结果是 TRUE 或 FALSE。利用通配符可以在不完全确定比较值的情形下创建一个比较特定数据的搜索模式,并置于关键字 LIKE 之后。可以在搜索模式的任意位置使用通配符,并且可以使用多个通配符。MySQL 支持的通配符有以下两种:1) 百分号(%)百分号是 MySQL 中常用的一种通配符,在过滤条件中,百分号可以表示任何字符串,并且该字符串可以出现任意次。使用百分号通配符要注意以下几点:MySQL 默认是不区分大小写的,若要区分大小写,则需要更换字符集的校对规则。百分号不匹配空值。百分号可以代表搜索模式中给定位置的 0 个、1 个或多个字符。尾空格可能会干扰通配符的匹配,一般可以在搜索模式的最后附加一个百分号。2) 下划线(_)下划线通配符和百分号通配符的用途一样,下画线只匹配单个字符,而不是多个字符,也不是 0 个字符。注意:不要过度使用通配符,对通配符检索的处理一般会比其他检索方式花费更长的时间。【实例 4】在 tb_students_info 表中,查找所有以“T”字母开头的学生姓名,输入的 SQL 的语句和执行结果如下所示。mysql> SELECT name FROM tb_students_info -> WHERE name LIKE 'T%'; +--------+ | name | +--------+ | Thomas | | Tom | +--------+ 2 rows in set (0.12 sec)注意:在搜索匹配时,通配符“%”可以放在不同位置。【实例 5】在 tb_students_info 表中,查找所有包含“e”字母的学生姓名,输入的 SQL 的语句和执行结果如下所示。mysql> SELECT name FROM tb_students_info -> WHERE name LIKE '%e%'; +-------+ | name | +-------+ | Green | | Henry | | Jane | +-------+ 3 rows in set (0.00 sec)由执行结果可以看出,该语句查询字符串中包含字母 e 的学生的姓名,只要名字中有字母 e,其前面或后面无论有多少个字符,都满足查询的条件。【实例 6】在 tb_students_info 表中,查找所有以字母“y”结尾,且“y”前面只有 4 个字母的学生的姓名,输入的 SQL 语句和执行结果如下所示。mysql> SELECT name FROM tb_students_info -> WHERE name LIKE '____y'; +-------+ | name | +-------+ | Henry | +-------+ 1 row in set (0.00 sec)日期字段作为条件的查询语句以日期字段作为条件,可以使用比较运算符设置查询条件,也可以使用 BETWEEN AND 运算符查询某个范围内的值。BETWEEN AND 用来查询某个范围内的值,该操作符需要两个参数,即范围的开始值和结束值,若字段值满足指定的范围查询条件,则这些记录被返回。【实例 7】在表 tb_students_info 中查询注册日期在 2016-01-01 之前的学生的信息,输入的 SQL 语句和执行结果如下所示。mysql> SELECT * FROM tb_students_info -> WHERE login_date<'2016-01-01'; +----+-------+---------+------+------+--------+------------+ | id | name | dept_id | age | sex | height | login_date | +----+-------+---------+------+------+--------+------------+ | 1 | Dany | 1 | 25 | F | 160 | 2015-09-10 | | 3 | Henry | 2 | 23 | M | 185 | 2015-05-31 | | 6 | John | 2 | 21 | M | 172 | 2015-11-11 | | 8 | Susan | 4 | 23 | F | 170 | 2015-10-01 | +----+-------+---------+------+------+--------+------------+ 4 rows in set (0.04 sec)【实例 8】在表 tb_students_info 中查询注册日期在 2015-10-01 和 2016-05-01 之间的学生的信息,输入的 SQL 语句和执行结果如下所示。mysql> SELECT * FROM tb_students_info -> WHERE login_date -> BETWEEN '2015-10-01' -> AND '2016-05-01'; +----+-------+---------+------+------+--------+------------+ | id | name | dept_id | age | sex | height | login_date | +----+-------+---------+------+------+--------+------------+ | 5 | Jim | 1 | 24 | M | 175 | 2016-01-15 | | 6 | John | 2 | 21 | M | 172 | 2015-11-11 | | 7 | Lily | 6 | 22 | F | 165 | 2016-02-26 | | 8 | Susan | 4 | 23 | F | 170 | 2015-10-01 | +----+-------+---------+------+------+--------+------------+ 4 rows in set (0.02 sec)在使用 MySQL SELECT语句时,可以使用 WHERE 子句来指定查询条件,从 FROM 子句的中间结果中选取适当的数据行,达到数据过滤的效果。语法格式如下:WHERE <查询条件> {<判定运算1>,<判定运算2>,…}其中,判定运算其结果取值为 TRUE、FALSE 和 UNKNOWN。判定运算的语法分类如下:<表达式1>{=|<|<=|>|>=|<=>|<>|!=}<表达式2><表达式1>[NOT]LIKE<表达式2><表达式1>[NOT][REGEXP|RLIKE]<表达式2><表达式1>[NOT]BETWEEN<表达式2>AND<表达式3><表达式1>IS[NOT]NULL单一条件的查询语句【实例 1】在表 tb_students_info 中查询身高为 170cm 的学生的姓名,输入的 SQL 语句和行结果如下所示。mysql> use test_db Database changed mysql> SELECT name,height -> FROM tb_students_info -> WHERE height=170; +-------+--------+ | name | height | +-------+--------+ | Susan | 170 | +-------+--------+ 1 row in set (0.17 sec)该语句采用了简单的相等过滤,查询一个指定列 height 的具体值 170。【实例 2】查询年龄小于 22 的学生的姓名,输入的 SQL 语句和执行结果如下所示。mysql> SELECT name,age -> FROM tb_students_info -> WHERE age<22; +------+------+ | name | age | +------+------+ | John | 21 | +------+------+ 1 row in set (0.05 sec)可以看到,查询结果中所有记录的 age 字段的值均小于 22 岁,而大于或等于 22 岁的记录没有被返回。多条件的查询语句使用 SELECT 查询时,可以增加查询的限制条件,这样可以使查询的结果更加精确。MySQL 在 WHERE 子句中使用 AND 操作符限定只有满足所有查询条件的记录才会被返回。可以使用 AND 连接两个甚至多个查询条件,多个条件表达式之间用 AND 分开。【实例 3】在 tb_students_info 表中查询 age 大于 21,并且 height 大于等于 175 的学生的信息,输入的 SQL 语句和执行结果如下所示。mysql> SELECT * FROM tb_students_info -> WHERE age>21 AND height>=175; +----+--------+---------+------+------+--------+------------+ | id | name | dept_id | age | sex | height | login_date | +----+--------+---------+------+------+--------+------------+ | 3 | Henry | 2 | 23 | M | 185 | 2015-05-31 | | 5 | Jim | 1 | 24 | M | 175 | 2016-01-15 | | 9 | Thomas | 3 | 22 | M | 178 | 2016-06-07 | +----+--------+---------+------+------+--------+------------+ 3 rows in set (0.06 sec)注意:上例的 WHERE 子句中只包含一个 AND 语句,把两个过滤条件组合在一起,实际上可以添加多个 AND 过滤条件,增加条件的同时增加一个 AND 关键字。使用 LIKE 的模糊查询字符串匹配的语法格式如下:<表达式1> [NOT] LIKE <表达式2>字符串匹配是一种模式匹配,使用运算符 LIKE 设置过滤条件,过滤条件使用通配符进行匹配运算,而不是判断是否相等进行比较。相互间进行匹配运算的对象可以是 CHAR、VARCHAR、TEXT、DATETIME 等数据类型。运算返回的结果是 TRUE 或 FALSE。利用通配符可以在不完全确定比较值的情形下创建一个比较特定数据的搜索模式,并置于关键字 LIKE 之后。可以在搜索模式的任意位置使用通配符,并且可以使用多个通配符。MySQL 支持的通配符有以下两种:1) 百分号(%)百分号是 MySQL 中常用的一种通配符,在过滤条件中,百分号可以表示任何字符串,并且该字符串可以出现任意次。使用百分号通配符要注意以下几点:MySQL 默认是不区分大小写的,若要区分大小写,则需要更换字符集的校对规则。百分号不匹配空值。百分号可以代表搜索模式中给定位置的 0 个、1 个或多个字符。尾空格可能会干扰通配符的匹配,一般可以在搜索模式的最后附加一个百分号。2) 下划线(_)下划线通配符和百分号通配符的用途一样,下画线只匹配单个字符,而不是多个字符,也不是 0 个字符。注意:不要过度使用通配符,对通配符检索的处理一般会比其他检索方式花费更长的时间。【实例 4】在 tb_students_info 表中,查找所有以“T”字母开头的学生姓名,输入的 SQL 的语句和执行结果如下所示。mysql> SELECT name FROM tb_students_info -> WHERE name LIKE 'T%'; +--------+ | name | +--------+ | Thomas | | Tom | +--------+ 2 rows in set (0.12 sec)注意:在搜索匹配时,通配符“%”可以放在不同位置。【实例 5】在 tb_students_info 表中,查找所有包含“e”字母的学生姓名,输入的 SQL 的语句和执行结果如下所示。mysql> SELECT name FROM tb_students_info -> WHERE name LIKE '%e%'; +-------+ | name | +-------+ | Green | | Henry | | Jane | +-------+ 3 rows in set (0.00 sec)由执行结果可以看出,该语句查询字符串中包含字母 e 的学生的姓名,只要名字中有字母 e,其前面或后面无论有多少个字符,都满足查询的条件。【实例 6】在 tb_students_info 表中,查找所有以字母“y”结尾,且“y”前面只有 4 个字母的学生的姓名,输入的 SQL 语句和执行结果如下所示。mysql> SELECT name FROM tb_students_info -> WHERE name LIKE '____y'; +-------+ | name | +-------+ | Henry | +-------+ 1 row in set (0.00 sec)日期字段作为条件的查询语句以日期字段作为条件,可以使用比较运算符设置查询条件,也可以使用 BETWEEN AND 运算符查询某个范围内的值。BETWEEN AND 用来查询某个范围内的值,该操作符需要两个参数,即范围的开始值和结束值,若字段值满足指定的范围查询条件,则这些记录被返回。【实例 7】在表 tb_students_info 中查询注册日期在 2016-01-01 之前的学生的信息,输入的 SQL 语句和执行结果如下所示。mysql> SELECT * FROM tb_students_info -> WHERE login_date<'2016-01-01'; +----+-------+---------+------+------+--------+------------+ | id | name | dept_id | age | sex | height | login_date | +----+-------+---------+------+------+--------+------------+ | 1 | Dany | 1 | 25 | F | 160 | 2015-09-10 | | 3 | Henry | 2 | 23 | M | 185 | 2015-05-31 | | 6 | John | 2 | 21 | M | 172 | 2015-11-11 | | 8 | Susan | 4 | 23 | F | 170 | 2015-10-01 | +----+-------+---------+------+------+--------+------------+ 4 rows in set (0.04 sec)【实例 8】在表 tb_students_info 中查询注册日期在 2015-10-01 和 2016-05-01 之间的学生的信息,输入的 SQL 语句和执行结果如下所示。mysql> SELECT * FROM tb_students_info -> WHERE login_date -> BETWEEN '2015-10-01' -> AND '2016-05-01'; +----+-------+---------+------+------+--------+------------+ | id | name | dept_id | age | sex | height | login_date | +----+-------+---------+------+------+--------+------------+ | 5 | Jim | 1 | 24 | M | 175 | 2016-01-15 | | 6 | John | 2 | 21 | M | 172 | 2015-11-11 | | 7 | Lily | 6 | 22 | F | 165 | 2016-02-26 | | 8 | Susan | 4 | 23 | F | 170 | 2015-10-01 | +----+-------+---------+------+------+--------+------------+ 4 rows in set (0.02 sec)
-
1、MySQL8.0.16解压其中dada文件夹和my.ini配置文件是解压后手动加入的,如下图所示2、新建配置文件my.ini放在D:\Free\mysql-8.0.16-winx64目录下[mysql] # 设置mysql客户端默认字符集 default-character-set=utf8 [mysqld] #设置3306端口 port = 3306 # 设置mysql的安装目录 basedir=D:\Free\mysql-8.0.16-winx64 # 设置mysql数据库的数据的存放目录 datadir=D:\Free\mysql-8.0.16-winx64\data # 允许最大连接数 max_connections=200 # 允许连接失败的次数。这是为了防止有人从该主机试图攻击数据库系统 max_connect_errors=20 # 服务端使用的字符集默认为8比特编码的latin1字符集 character-set-server=utf8 # 创建新表时将使用的默认存储引擎 default-storage-engine=INNODB # 忽略密码 # skip-grant-tables如图:3、初始化MYSQL配置管理员身份打开Windows PowerShell,并进入D:\Free\mysql-8.0.16-winx64\bin目录,执行如下命令:mysqld --initialize --console执行成功后如下图所示:其中,[Note] [MY-010454] [Server] A temporary password is generated for root@localhost:后面的是初始化密码,即diK3i1dH=k8b初始化Mysql配置之后,data目录下会生成相关文件,如下所示4、安装MySQL服务,并启动服务安装服务的命令为:mysqld --install 服务名,由于我电脑已配置安装了mysql服务,此处用mysql8作为服务名,如下所示mysqld --install mysql8启动服务命令为:net start 服务名net start mysql8如下截图5、登录MySQL并修改root密码使用默认分配的密码(即diK3i1dH=k8b)进行登录mysql -uroot -pdiK3i1dH=k8b登录成功后,修改密码为passwordalter user 'root'@'localhost' IDENTIFIED BY 'password';刷新一下即可flush privileges;如下图所示6、重新登录新密码也能成功登录!
-
1.解压mysql-8.0.21-winx642.配置环境变量,地址写到bin文件夹下3.创建配置文件,命名为 my.ini,内容如下[mysql] # 设置mysql客户端默认字符集 default-character-set=utf8 [mysqld] interactive_timeout=28800000 wait_timeout=28800000 # 设置3306端口 port = 3306 # 设置mysql的安装目录 basedir=D:\ProgramFiles\mysql-8.0.21-winx64\bin # 设置mysql数据库的数据的存放目录 datadir=D:\ProgramFiles\mysql-8.0.21-winx64\data # 允许最大连接数 max_connections=200 # 设置mysql服务端默认字符集 character-set-server=utf8 # 创建新表时将使用的默认存储引擎 default-storage-engine=INNODB4.安装mysql服务,输入mysqld –install如果报以下错误,打开cmd.exe程序的时候选择“用管理员身份打开5.初始化mysql,输入以下命令,mysql目录下会生成 data 文件夹mysqld –-initialize如果没有生成data文件夹,则使用以下命令mysqld --initialize-insecure --user=mysql6.启动mysql,设置密码net start mysql mysql admin -u root -p password设置密码失败,百度一下,别人文档中有提到打开mysql根目录下的data文件夹,找到后缀是.err的文件以文本打开找到password临时密码(可以ctrl+f搜索)然后在cmd中输入该临时密码,但是我这里的.err文件中没有password,所以使用重置密码的方法7.如果启动了mysql服务,就要停止mysql服务,使用命令net stop mysql8.使用mysqld –skip-grant-tables实测在mysql8.0.21中已失效,现使用以下命令进入免密登录模式mysqld --console --skip-grant-tables --shared-memory9.另外开一个cmd窗口,使用mysql直接无密登录。输入以下命令回车,提示输入密码时再按回车进入mysql -uroot -p10.选择数据库,输入use mysql11.密码置空update user set authentication_string='' where user=‘root';12.提示成功,一定要使用一下命令,再退出flush privileges; exit;13.关闭免密登录模式的cmd窗口,启动mysql服务net start mysql14.步骤12密码已经置空,所以无密码状态登录MySQL,输入登录命令:mysql -u root -p15.修改密码alter user ‘root'@‘localhost' identified with mysql_native_password BY ‘123456';16.刷新权限后退出,大功告成flush privileges; exit;
-
1、选取最适用的字段属性MySQL可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快。因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小。例如,在定义邮政编码这个字段时,如果将其设置为CHAR(255),显然给数据库增加了不必要的空间,甚至使用VARCHAR这种类型也是多余的,因为CHAR(6)就可以很好的完成任务了。同样的,如果可以的话,我们应该使用MEDIUMINT而不是BIGIN来定义整型字段。另外一个提高效率的方法是在可能的情况下,应该尽量把字段设置为NOTNULL,这样在将来执行查询的时候,数据库不用去比较NULL值。对于某些文本字段,例如“省份”或者“性别”,我们可以将它们定义为ENUM类型。因为在MySQL中,ENUM类型被当作数值型数据来处理,而数值型数据被处理起来的速度要比文本类型快得多。这样,我们又可以提高数据库的性能。2、使用连接(JOIN)来代替子查询(Sub-Queries)MySQL从4.1开始支持SQL的子查询。这个技术可以使用SELECT语句来创建一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中。例如,我们要将客户基本信息表中没有任何订单的客户删除掉,就可以利用子查询先从销售信息表中将所有发出订单的客户ID取出来,然后将结果传递给主查询,如下所示:DELETEFROMcustomerinfo WHERECustomerIDNOTin(SELECTCustomerIDFROMsalesinfo)使用子查询可以一次性的完成很多逻辑上需要多个步骤才能完成的SQL操作,同时也可以避免事务或者表锁死,并且写起来也很容易。但是,有些情况下,子查询可以被更有效率的连接(JOIN)..替代。例如,假设我们要将所有没有订单记录的用户取出来,可以用下面这个查询完成:SELECT*FROMcustomerinfo WHERECustomerIDNOTin(SELECTCustomerIDFROMsalesinfo)如果使用连接(JOIN)..来完成这个查询工作,速度将会快很多。尤其是当salesinfo表中对CustomerID建有索引的话,性能将会更好,查询如下:SELECT*FROMcustomerinfo LEFTJOINsalesinfoONcustomerinfo.CustomerID=salesinfo.CustomerID WHEREsalesinfo.CustomerIDISNULL连接(JOIN)..之所以更有效率一些,是因为MySQL不需要在内存中创建临时表来完成这个逻辑上的需要两个步骤的查询工作。3、使用联合(UNION)来代替手动创建的临时表MySQL从4.0的版本开始支持union查询,它可以把需要使用临时表的两条或更多的select查询合并的一个查询中。在客户端的查询会话结束的时候,临时表会被自动删除,从而保证数据库整齐、高效。使用union来创建查询的时候,我们只需要用UNION作为关键字把多个select语句连接起来就可以了,要注意的是所有select语句中的字段数目要想同。下面的例子就演示了一个使用UNION的查询。SELECTName,PhoneFROMclientUNION SELECTName,BirthDateFROMauthorUNION SELECTName,SupplierFROMproduct4、事务尽管我们可以使用子查询(Sub-Queries)、连接(JOIN)和联合(UNION)来创建各种各样的查询,但不是所有的数据库操作都可以只用一条或少数几条SQL语句就可以完成的。更多的时候是需要用到一系列的语句来完成某种工作。但是在这种情况下,当这个语句块中的某一条语句运行出错的时候,整个语句块的操作就会变得不确定起来。设想一下,要把某个数据同时插入两个相关联的表中,可能会出现这样的情况:第一个表中成功更新后,数据库突然出现意外状况,造成第二个表中的操作没有完成,这样,就会造成数据的不完整,甚至会破坏数据库中的数据。要避免这种情况,就应该使用事务,它的作用是:要么语句块中每条语句都操作成功,要么都失败。换句话说,就是可以保持数据库中数据的一致性和完整性。事物以BEGIN关键字开始,COMMIT关键字结束。在这之间的一条SQL操作失败,那么,ROLLBACK命令就可以把数据库恢复到BEGIN开始之前的状态。BEGIN; INSERTINTOsalesinfoSETCustomerID=14;UPDATEinventorySETQuantity=11WHEREitem='book';COMMIT;事务的另一个重要作用是当多个用户同时使用相同的数据源时,它可以利用锁定数据库的方法来为用户提供一种安全的访问方式,这样可以保证用户的操作不被其它的用户所干扰。5、锁定表尽管事务是维护数据库完整性的一个非常好的方法,但却因为它的独占性,有时会影响数据库的性能,尤其是在很大的应用系统中。由于在事务执行的过程中,数据库将会被锁定,因此其它的用户请求只能暂时等待直到该事务结束。如果一个数据库系统只有少数几个用户来使用,事务造成的影响不会成为一个太大的问题;但假设有成千上万的用户同时访问一个数据库系统,例如访问一个电子商务网站,就会产生比较严重的响应延迟。其实,有些情况下我们可以通过锁定表的方法来获得更好的性能。下面的例子就用锁定表的方法来完成前面一个例子中事务的功能。LOCKTABLEinventoryWRITESELECTQuantityFROMinventoryWHEREItem='book'; ... UPDATEinventorySETQuantity=11WHEREItem='book';UNLOCKTABLES这里,我们用一个select语句取出初始数据,通过一些计算,用update语句将新值更新到表中。包含有WRITE关键字的LOCKTABLE语句可以保证在UNLOCKTABLES命令被执行之前,不会有其它的访问来对inventory进行插入、更新或者删除的操作。6、使用外键锁定表的方法可以维护数据的完整性,但是它却不能保证数据的关联性。这个时候我们就可以使用外键。例如,外键可以保证每一条销售记录都指向某一个存在的客户。在这里,外键可以把customerinfo表中的CustomerID映射到salesinfo表中CustomerID,任何一条没有合法CustomerID的记录都不会被更新或插入到salesinfo中。CREATETABLEcustomerinfo( CustomerIDINTNOTNULL,PRIMARYKEY(CustomerID))TYPE=INNODB; CREATETABLEsalesinfo( SalesIDINTNOTNULL,CustomerIDINTNOTNULL, PRIMARYKEY(CustomerID,SalesID), FOREIGNKEY(CustomerID)REFERENCEScustomerinfo(CustomerID)ONDELETECASCADE)TYPE=INNODB;注意例子中的参数“ONDELETECASCADE”。该参数保证当customerinfo表中的一条客户记录被删除的时候,salesinfo表中所有与该客户相关的记录也会被自动删除。如果要在MySQL中使用外键,一定要记住在创建表的时候将表的类型定义为事务安全表InnoDB类型。该类型不是MySQL表的默认类型。定义的方法是在CREATETABLE语句中加上TYPE=INNODB。如例中所示。7、使用索引索引是提高数据库性能的常用方法,它可以令数据库服务器以比没有索引快得多的速度检索特定的行,尤其是在查询语句当中包含有MAX(),MIN()和ORDERBY这些命令的时候,性能提高更为明显。那该对哪些字段建立索引呢?一般说来,索引应建立在那些将用于JOIN,WHERE判断和ORDERBY排序的字段上。尽量不要对数据库中某个含有大量重复的值的字段建立索引。对于一个ENUM类型的字段来说,出现大量重复值是很有可能的情况例如customerinfo中的“province”..字段,在这样的字段上建立索引将不会有什么帮助;相反,还有可能降低数据库的性能。我们在创建表的时候可以同时创建合适的索引,也可以使用ALTERTABLE或CREATEINDEX在以后创建索引。此外,MySQL从版本3.23.23开始支持全文索引和搜索。全文索引在MySQL中是一个FULLTEXT类型索引,但仅能用于MyISAM类型的表。对于一个大的数据库,将数据装载到一个没有FULLTEXT索引的表中,然后再使用ALTERTABLE或CREATEINDEX创建索引,将是非常快的。但如果将数据装载到一个已经有FULLTEXT索引的表中,执行过程将会非常慢。8、优化的查询语句绝大多数情况下,使用索引可以提高查询的速度,但如果SQL语句使用不恰当的话,索引将无法发挥它应有的作用。下面是应该注意的几个方面。首先,最好是在相同类型的字段间进行比较的操作。在MySQL3.23版之前,这甚至是一个必须的条件。例如不能将一个建有索引的INT字段和BIGINT字段进行比较;但是作为特殊的情况, 在CHAR类型的字段和VARCHAR类型字段的字段大小相同的时候,可以将它们进行比较。其次,在建有索引的字段上尽量不要使用函数进行操作。例如,在一个DATE类型的字段上使用YEAE()函数时,将会使索引不能发挥应有的作用。 所以,下面的两个查询虽然返回的结果一样,但后者要比前者快得多。第三,在搜索字符型字段时,我们有时会使用LIKE关键字和通配符,这种做法虽然简单,但却也是以牺牲系统性能为代价的。例如下面的查询将会比较表中的每一条记录。 SELECT*FROMbooks WHEREnamelike"MySQL%"但是如果换用下面的查询,返回的结果一样,但速度就要快上很多:SELECT*FROMbooks WHEREname>="MySQL"andname<"MySQM"最后,应该注意避免在查询中让MySQL进行自动类型转换,因为转换过程也会使索引变得不起作用。
-
备份数据库,这是必须会用到的,今天上午花了几个小时整理了一下,结果不错。下面详细的走一遍一丶选择一个比较大位置来保存备份文件(创建文件就行)使用mkdir来创建文件夹,这个简单。二丶检查有没安装crond,如果没有,先安装rpm -qa|grep cron安装后会是一般没有安装,所以先 yum -y install vixie-cron然后再yum -y install crontabs这样服务就安装好了。三丶写备份脚本vi /var/spool/cron/name.sh因为cron安装在var/spool/cron这里,我就将脚本创建在这,name.sh你可以随意起名,然后回车会进入这个脚本文件的编辑页面 到这一步是有丶东西的,第一个就是vi的命令,最重要是里面有一个光标,, 删除一个字符是光标对准它,然后按d删除整行就dd想要替换这个字符就按r并且输入一个字符 然后编辑一行就按c然后方向左右键,这时候会删除一个,不是很清楚为什么要删除一个,所以我一般光标选中空格的地方。更多命令可以去这里vi命令,还有就是退出编辑的命令:wq保存并退出, 然后:q!强制退出不保存,更多命令去vi退出编辑命令。这些常规操作就这样了,接着我们来写备份脚本,我的是上面这样的。#!/bin/bash # Name:name.sh # This is a ShellScript For Auto DB Backup and Delete old Backup backupdir=/root/application/bak/mysqldata time=` date +%Y%m%d%H ` /usr/local/mysql/bin/mysqldump -u root -p123456a test | gzip > $backupdir/name1$time.sql.gz find $backupdir -name "name_*.sql.gz" -type f -mtime +7 -exec rm {} \; > /dev/null 2>&1/usr/local/mysql/bin/mysqldump这个是我的MySQL路径是这里,指定MySQL的bin里的mysqldump程序来执行,backupdir是sql备份文件的文件夹-uroot就是数据库用户是root 然后-p123456a就是数据库密码是123456a 然后test是数据库名,后面$都是引用前面声明,$time.sql这是创建sql文件,find就是找文件 $backupdir后面必须要有/ 不然找不到 然后-name这些就找文件名了-mtime +7是每隔7天删除一次,我们等下测试每分钟备份一次所以要删除7分钟之前的文件,所以用-mmin +7 所以脚本就建好了。四丶为脚本添加执行权限这个简单,就直接 chmod +x /var/spool/cron/name.sh 前面chmod +x不要动,后面是脚本文件的绝对路径五丶修改 vi /etc/crontab,就是添加定时任务来定时执行脚本文件,这里也是vi的编辑命令,所以添加有点麻烦,加上一句00 3 * * * /var/spool/cron/name.sh 就行 前面00是分钟 3 是时钟 ***不用管 。因为等下要测试,每分钟执行脚本文件是** * * * /var/spool/cron/name.sh 就是5个*六丶重启crontabservice crond restart 因为我是全局的,所以可以直接service crond restart 。因为要测试,所以会改脚本文件跟执行vi /etc/crontab这样。所以基本是先改-mmin +7来测试是否删除7分钟前的sql文件,再就是vi /etc/crontab来添加** * * * /var/spool/cron/name.sh 来测试每分钟备份一次,再service crond restart重启看效果。如果有效就改成正常的-mtime +7 跟00 3 * * * /var/spool/cron/name.sh 来晚上3点备份数据库。
-
Mysql的Bin log数据恢复:不小心删除数据库前言:因为不小心删除了测试机器上Mysql的一整个数据库Schema,因为是测试机所以没有做备份,现在通过MySQL的Bin log方式恢复到删除以前的数据库。当然做Bin log的数据恢复前提是已经打开Bin log的功能,如果又没做数据备份,又没打开Bin log日志,那你就可能需要考虑快照等其它方式从系统的角度去恢复。Bin log 常用于数据增量备份和恢复,以及数据库主从复制。如果没有开启,可以通过如下方式打开:1、打开mysql的binlog功能mysql是支持增量备份,但要打开mysql的bin log功能。修改mysql的配置文件。linux是/etc/my.cnf,windows是mysql的安装目录/my.ini在[mysqld]下面加上log-bin一行代码,如下面:# Replication Master Server (default) # binary logging is required for replication log-bin=mysql-bin # binary logging format - mixed recommended binlog_format=mixed。2、用如下方式查看二进制日志状态:是否开启mysql> show variables like 'log_%';3、查看所有二进制日志文件:mysql> show libary logs;mysql> show binary logs; +------------------+-----------+ | Log_name | File_size | +------------------+-----------+ | mysql-bin.000001 | 201 | | mysql-bin.000002 | 351 | | mysql-bin.000003 | 276 | | mysql-bin.000004 | 201 | | mysql-bin.000005 | 16509 |4、Mysql查看二进制日志文件的操作日志#mysqlbinlog --start-position=0 /mydata/data/mysql-bin.000089[root@test mysql]# mysqlbinlog --start-position=0 --stop-position=500 mysql-bin.000091 Warning: option 'start-position': unsigned value 0 adjusted to 4 /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/; /*!40019 SET @@session.max_insert_delayed_threads=0*/; /*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/; DELIMITER /*!*/; # at 4 #151022 18:00:43 server id 1 end_log_pos 107 Start: binlog v 4, server v 5.5.38-log created 151022 18:00:43 at startup # Warning: this binlog is either in use or was not closed properly. ROLLBACK/*!*/; BINLOG ' y7MoVg8BAAAAZwAAAGsAAAABAAQANS41LjM4LWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAADLsyhWEzgNAAgAEgAEBAQEEgAAVAAEGggAAAAICAgCAA== '/*!*/; # at 107 #151022 23:27:50 server id 1 end_log_pos 198 Query thread_id=2 exec_time=0 error_code=0 SET TIMESTAMP=1445527670/*!*/; SET @@session.pseudo_thread_id=2/*!*/; SET @@session.foreign_key_checks=0, @@session.sql_auto_is_null=0, @@session.unique_checks=0, @@session.autocommit=1/*!*/; SET @@session.sql_mode=1608515584/*!*/; SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/; /*!\C utf8 *//*!*/; SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/; SET @@session.lc_time_names=0/*!*/; SET @@session.collation_database=DEFAULT/*!*/; DROP SCHEMA IF EXISTS `pandora`<pre name="code" class="sql">/*!*/; # at 198 #151022 23:27:50 server id 1 end_log_pos 346 Query thread_id=2 exec_time=0 error_code=05、通过Bin log恢复数据. 因为我整个Schema都删掉了,又没备份,正好开启了bin log日志,所以把历史的bin-log都重新执行了一遍,重新恢复到误删以前的版本,(我这里总共有91个文件,批量处理的):(9999999999999:是为了省掉去查找每一个bin-log日志文件的起始结束位置,设的一个无穷大的数字,简化操作.)#mysqlbinlog /var/lib/mysql/mysql-bin.000001 --start-position=0 --stop-position=9999999999999 | mysql -uroot -p123456 #mysqlbinlog /var/lib/mysql/mysql-bin.000002 --start-position=0 --stop-position=9999999999999 | mysql -uroot -p123456 #mysqlbinlog /var/lib/mysql/mysql-bin.000003 --start-position=0 --stop-position=9999999999999 | mysql -uroot -p123456 ... ...所以总结结论是:切记一定要定期备份;有备份的话恢复也快一点,可以从备份的时间点做增量备份,不需要像我这里从头开始91个文件全部批量跑一遍,当然我用编辑器批量处理的也还算快;另外一定要打开Bin-log日志,如果没做备份也可以通过Bin-log日志恢复。操作要小心。其它:1、还有个sql_logmysql> show variables like 'sql_log_%';Mysql开启关闭sql二进制日志:mysql> set sql_log_bin=0; //关闭set session sql_log_bin=0;2、查找文件位置:find / -name my.cnf3、linux 查看当前所在目录的全路径pwd命令:/var/lib/mysql4、查看当前binary log的情况:mysql>show master status;5、在my.cnf/my.ini中设定binary logs回滚天数:expire_logs_days = 76、查看Master的bin log日志mysql> show master logs; +-----------------+-----------+ | Log_name | File_size | +-----------------+-----------+ | log-bin.000001 | 98 | +-----------------+-----------+ 1 row in set (0.00 sec) ---------------------
-
1、在网上找了许久都没有找到判断表是否存在,然后模糊删除的。但是最后找到了一个曲线救国的方法。需求:删除表中后缀是 _待删除 的表1、第一步,找到所有的这样的表,并且拼装好删除表的sqlSelect CONCAT( 'DROP TABLE IF EXISTS ', table_name, ';' ) FROM information_schema.tables Where table_name LIKE '%_待删除';执行结果2、第二步:去一一执行删除语句,有能力的可以去写一个脚本执行什么的3、sql解析3-1 :concat 字符串拼接3-2 :DROP TABLE IF EXISTS equi_accp_info__待删除; --判断这个表是否存在,如果存在就删除补充知识:mysql 判断表字段是否存在,然后修改我就废话不多说了,大家还是直接看代码吧~-- 判断 vrv_paw_rule 表是否存在 thresholdMin 字段,不存在则添加; 存在则修改字段类型 DELIMITER ?? DROP PROCEDURE IF EXISTS schema_change?? CREATE PROCEDURE schema_change() BEGIN IF NOT EXISTS (SELECT * FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'vrv_paw_rule' AND column_name = 'thresholdMin') THEN ALTER TABLE vrv_paw_rule ADD COLUMN thresholdMin BIGINT; ELSE ALTER TABLE vrv_paw_rule MODIFY COLUMN thresholdMin BIGINT ; END IF; END?? DELIMITER ; CALL schema_change();delimit命令:就是告诉mysql解释器,该段命令是否已经结束了,mysql是否可以执行了,即改变输入结束符。默认情况下,delimiter是分号“;”。在命令行客户端中,如果有一行命令以分号结束,那么回车后,mysql将会执行该命令。但有时候,不希望MySQL这么做。因为可能输入较多的语句,且语句中包含有分号。默认情况下,不可能等到用户把这些语句全部输入完之后,再执行整段语句。因为mysql一遇到分号,它就要自动执行。这种情况下,就可以使用delimiter,把delimiter后面换成其它符号,如//或$$。此时,delimiter作用就是对整个小段语句做一个简单的封装。此命令多用在定义子程序,触发程序等mysql自己内嵌小程序中。
-
今天一大早小姐姐给我打电话:“靓仔,昨晚我往数据库导了几十万条数据,然后在web界面很多都搜不到,你们系统做的啥玩意儿啊?这么多BUG!得啵得啵得…”(省略2000字)又习惯性的喷了一遍我们这个项目做的辣鸡~~得得得,客户随便喷,我就当吃了个早饭了嗝儿~嗯,真饱;先测试一下客户给我的错误示例(果然搜不到),然后排查一下昨天的数据是否有问题,发现昨天客户用excel导入的数据中,存在很多\r\n这种换行符和回车符。如:库中数据为:“换行符\n换行符\n换行符”,然后在界面通过如下SQL查询,那自然是搜不到咯!SELECT * from `LOL` where name = '换行符换行符换行符';换行符:CHAR(10) = "\n"回车符: CHAR(13) = "\r"在MySQL中,回车符、换行符都属于char类型,放到varchar中时,在navcat等插件上是不显示的,需要在mysql终端和navcat对比才能看出来(坑啊~)navcat插件显示如下:MySQL终端显示如下:(回车符\r还导致数据结果直接返回了,只显示了一部分,MySQL你让我说你啥好)mysql> select * from `LOL`; +----+-------------------------------+-----------+-------+ | id | hero_title | hero_name | price | +----+-------------------------------+-----------+-------+ | 1 | D刀锋之影 | 泰隆 | 6300 | | 2 | X迅捷斥候 | 提莫 | 6300 | | 8 | 换行符 换行符 换行符 | 换行符 | 450 | 回车符 | 回车符 | 450 | +----+-------------------------------+-----------+-------+ 4 rows in set (0.00 sec)1、如何去掉换行符,回车符如果条件允许,建议直接通过语句清除掉换行符和回车符,如下:去除"hero_title"列中所有换行符 (通过以下两种方式都可以)-- 去除"hero_title"列中所有换行符 (通过以下两种方式都可以) update `LOL` set hero_title = REPLACE(hero_title, '\n', ''); update `LOL` set hero_title = REPLACE(hero_title, char(10), '');– 去除"hero_title"列中所有回车符(通过以下两种方式都可以)-- 去除"hero_title"列中所有回车符 update `LOL` set hero_title = REPLACE(hero_title, '\r', ''); update `LOL` set hero_title = REPLACE(hero_title, char(13), '');2、SELECT如何忽略换行符,回车符号进行查询果条件不允许,比如客户“很激动”并向你吼道:不能动库里的数据!…我笑了~那怎么办呢?可以通过修改SQL来过滤掉换行符、回车符,但一定程度上会影响查询效率,而且要改很多代码,你懂得。铭记鲁迅先生说的:哪里有压迫,哪里就得有反抗!示例如下:-- 忽略掉换行符查询 SELECT * from `LOL` where REPLACE(hero_title, char(10), '') = '换行符换行符换行符'; -- 忽略掉回车符查询 SELECT * from `LOL` where REPLACE(hero_title, char(13), '') = '回车符回车符回车符'; -- 忽略掉换行符 & 回车符查询 SELECT * from `LOL` where REPLACE(REPLACE(hero_title, char(13), ''), char(10), '') = '回车符回车符回车符';3、经验总结类似的符号一般要求入库时就清理掉,如果必须保留也建议用其他自定义标识代替(如自创的唯一标识,我叫它大眼瞪小眼: o_O),后台程序中做替换处理,免得影响到索引效率。
-
问题介绍电脑在使用过程中死机,重启后发现mysql没有启动成功,查看错误日志发现是innodb出现问题导致mysql启动失败。错误日志 $ mysql.server start Starting MySQL . ERROR! The server quit without updating PID file (/usr/local/var/mysql/fdipzonedeMacBook-Air.local.pid). 22:08:37 mysqld_safe Starting mysqld daemon with databases from /usr/local/var/mysql 2016-04-23 22:08:38 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details). 2016-04-23 22:08:38 0 [Note] /usr/local/Cellar/mysql/5.6.24/bin/mysqld (mysqld 5.6.24) starting as process 3604 ... 2016-04-23 22:08:38 3604 [Warning] Setting lower_case_table_names=2 because file system for /usr/local/var/mysql/ is case insensitive 2016-04-23 22:08:38 3604 [Note] Plugin 'FEDERATED' is disabled. 2016-04-23 22:08:38 3604 [Note] InnoDB: Using atomics to ref count buffer pool pages 2016-04-23 22:08:38 3604 [Note] InnoDB: The InnoDB memory heap is disabled 2016-04-23 22:08:38 3604 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins 2016-04-23 22:08:38 3604 [Note] InnoDB: Memory barrier is not used 2016-04-23 22:08:38 3604 [Note] InnoDB: Compressed tables use zlib 1.2.3 2016-04-23 22:08:38 3604 [Note] InnoDB: Using CPU crc32 instructions 2016-04-23 22:08:38 3604 [Note] InnoDB: Initializing buffer pool, size = 128.0M 2016-04-23 22:08:38 3604 [Note] InnoDB: Completed initialization of buffer pool 2016-04-23 22:08:38 3604 [Note] InnoDB: Highest supported file format is Barracuda. 2016-04-23 22:08:38 3604 [Note] InnoDB: Log scan progressed past the checkpoint lsn 68929933440 2016-04-23 22:08:38 3604 [Note] InnoDB: Database was not shutdown normally! 2016-04-23 22:08:38 3604 [Note] InnoDB: Starting crash recovery. 2016-04-23 22:08:38 3604 [Note] InnoDB: Reading tablespace information from the .ibd files... 2016-04-23 22:08:38 3604 [ERROR] InnoDB: checksum mismatch in tablespace ./test_user/user_recommend_code#P#pmax.ibd (table test_user/user_recommend_code#P#pmax) 2016-04-23 22:08:38 3604 [Note] InnoDB: Page size:1024 Pages to analyze:64 2016-04-23 22:08:38 3604 [Note] InnoDB: Page size: 1024, Possible space_id count:0 2016-04-23 22:08:38 3604 [Note] InnoDB: Page size:2048 Pages to analyze:48 2016-04-23 22:08:38 3604 [Note] InnoDB: Page size: 2048, Possible space_id count:0 2016-04-23 22:08:38 3604 [Note] InnoDB: Page size:4096 Pages to analyze:24 2016-04-23 22:08:38 3604 [Note] InnoDB: Page size: 4096, Possible space_id count:0 2016-04-23 22:08:38 3604 [Note] InnoDB: Page size:8192 Pages to analyze:12 2016-04-23 22:08:38 3604 [Note] InnoDB: Page size: 8192, Possible space_id count:0 2016-04-23 22:08:38 3604 [Note] InnoDB: Page size:16384 Pages to analyze:6 2016-04-23 22:08:38 3604 [Note] InnoDB: VALID: space:2947354 page_no:3 page_size:16384 2016-04-23 22:08:38 3604 [Note] InnoDB: Page size: 16384, Possible space_id count:1 2016-04-23 22:08:38 3604 [Note] InnoDB: space_id:2947354, Number of pages matched: 1/1 (16384) 2016-04-23 22:08:38 3604 [Note] InnoDB: Chosen space:2947354 2016-04-23 22:08:38 3604 [Note] InnoDB: Restoring page 0 of tablespace 2947354 2016-04-23 22:08:38 3604 [Warning] InnoDB: Doublewrite does not have page_no=0 of space: 2947354 2016-04-23 22:08:38 7fff79b9e300 InnoDB: Operating system error number 2 in a file operation. InnoDB: The error means the system cannot find the path specified. InnoDB: If you are installing InnoDB, remember that you must create InnoDB: directories yourself, InnoDB does not create them. InnoDB: Error: could not open single-table tablespace file ./test_user/user_recommend_code#P#pmax.ibd InnoDB: We do not continue the crash recovery, because the table may become InnoDB: corrupt if we cannot apply the log records in the InnoDB log to it. InnoDB: To fix the problem and start mysqld: InnoDB: 1) If there is a permission problem in the file and mysqld cannot InnoDB: open the file, you should modify the permissions. InnoDB: 2) If the table is not needed, or you can restore it from a backup, InnoDB: then you can remove the .ibd file, and InnoDB will do a normal InnoDB: crash recovery and ignore that table. InnoDB: 3) If the file system or the disk is broken, and you cannot remove InnoDB: the .ibd file, you can set innodb_force_recovery > 0 in my.cnf InnoDB: and force InnoDB to continue crash recovery here.解决方法1.如果数据不重要或已经有备份,只需要恢复mysql启动进入mysql目录,一般是: /usr/local/var/mysql/删除ib_logfile*删除所有数据库物理目录(例如数据库为test_db,则执行rm -rf test_db)重启动mysql重新建立数据库或使用备份覆盖2.如果数据很重要且没有备份可以使用innodb_force_recovery参数,使mysqld跳过恢复步骤,启动mysqld,将数据导出然后重建数据库。innodb_force_recovery 可以设置为1-6,大的数字包含前面所有数字的影响 1、(SRV_FORCE_IGNORE_CORRUPT):忽略检查到的corrupt页。 2、(SRV_FORCE_NO_BACKGROUND):阻止主线程的运行,如主线程需要执行full purge操作,会导致crash。 3、(SRV_FORCE_NO_TRX_UNDO):不执行事务回滚操作。 4、(SRV_FORCE_NO_IBUF_MERGE):不执行插入缓冲的合并操作。 5、(SRV_FORCE_NO_UNDO_LOG_SCAN):不查看重做日志,InnoDB存储引擎会将未提交的事务视为已提交。 6、(SRV_FORCE_NO_LOG_REDO):不执行前滚的操作。在my.cnf(windows是my.ini)中加入innodb_force_recovery = 6 innodb_purge_thread = 0重启mysql这时只可以执行select,create,drop操作,但不能执行insert,update,delete操作执行逻辑导出,完成后将innodb_force_recovery=0,innodb_purge_threads=1,然后重建数据库,最后把导出的数据重新导入
-
一、什么是死锁官方定义如下:两个事务都持有对方需要的锁,并且在等待对方释放,并且双方都不会释放自己的锁。这个就好比你有一个人质,对方有一个人质,你们俩去谈判说换人。你让对面放人,对面让你放人。二、为什么会形成死锁看到这里,也许你会有这样的疑问,事务和谈判不一样,为什么事务不能使用完锁之后立马释放呢?居然还要操作完了之后一直持有锁?这就涉及到 MySQL 的并发控制了。MySQL的并发控制有两种方式,一个是 MVCC,一个是两阶段锁协议。那么为什么要并发控制呢?是因为多个用户同时操作 MySQL 的时候,为了提高并发性能并且要求如同多个用户的请求过来之后如同串行执行的一样(可串行化调度)。具体的并发控制这里不再展开。咱们继续深入讨论两阶段锁协议。两阶段锁协议(2PL)官方定义:两阶段锁协议是指所有事务必须分两个阶段对数据加锁和解锁,在对任何数据进行读、写操作之前,事务首先要获得对该数据的封锁;在释放一个封锁之后,事务不再申请和获得任何其他封锁。对应到 MySQL 上分为两个阶段:扩展阶段(事务开始后,commit 之前):获取锁收缩阶段(commit 之后):释放锁就是说呢,只有遵循两段锁协议,才能实现 可串行化调度。但是两阶段锁协议不要求事务必须一次将所有需要使用的数据加锁,并且在加锁阶段没有顺序要求,所以这种并发控制方式会形成死锁。三、MySQL 如何处理死锁?MySQL有两种死锁处理方式:等待,直到超时(innodb_lock_wait_timeout=50s)。发起死锁检测,主动回滚一条事务,让其他事务继续执行(innodb_deadlock_detect=on)。由于性能原因,一般都是使用死锁检测来进行处理死锁。死锁检测死锁检测的原理是构建一个以事务为顶点、锁为边的有向图,判断有向图是否存在环,存在即有死锁。回滚检测到死锁之后,选择插入更新或者删除的行数最少的事务回滚,基于 INFORMATION_SCHEMA.INNODB_TRX 表中的 trx_weight 字段来判断。四、如何避免发生死锁收集死锁信息:利用命令 SHOW ENGINE INNODB STATUS查看死锁原因。调试阶段开启 innodb_print_all_deadlocks,收集所有死锁日志。减少死锁:使用事务,不使用 lock tables 。保证没有长事务。操作完之后立即提交事务,特别是在交互式命令行中。如果在用 (SELECT ... FOR UPDATE or SELECT ... LOCK IN SHARE MODE),尝试降低隔离级别。修改多个表或者多个行的时候,将修改的顺序保持一致。创建索引,可以使创建的锁更少。最好不要用 (SELECT ... FOR UPDATE or SELECT ... LOCK IN SHARE MODE)。如果上述都无法解决问题,那么尝试使用 lock tables t1, t2, t3 锁多张表
-
了解mysql支持很多表类型的表(即存储引擎),如myisam、innodb、memory、archive、example等。每种存储引擎都有自己的优点和缺点,充分的理解每种存储引擎,有助于合理的使用它们。有人认为在同一个数据库中使用多种存储引擎很影响性能,其实这是一种十分错误的想法。实际上,除非是非常简单的数据库,否则的话,只使用一种存储引擎,对应用程序的性能来说是一个十分糟糕的行为。对数据库了解的人会根据每张表的作用不同来选择适当的存储引擎,这才是正确的做法。前面说过mysql的存储引擎很多,但是我个人在工作中运用最多的存储引擎有两个,一个是InnoDB,一个是MyISAM。我这里就聊聊这两个存储引擎,并比较下两者之间的区别。一、MyISAMMyISAM现在为mysql的默认存储引擎,如果在建表的时候,没有指定表类型,mysql就会默认使用MyISAM。MyISAM有一个很多人认为很重要,然而我却觉得没什么卵用的特性,那就是MyISAM表示独立于操作系统之外的。通俗点说就是你可以很轻松的将MyISAM表从windows移植到linux或者从linux移植到windows。这确实是个优点,可是哪个技术主管会有在决定用了一种操作系统一段时间后又要换服务器的操作系统的脑残行为,所有我认为这个优点没有什么实际的意义。MyISAM存储引擎是mysql组件中非常重要的一部分,在mysql中可以创建3种MyISAM格式的表——静态、动态和压缩。格式不需要单独指定,mysql会根据表结构自动选择最合适的格式。1、MyISAM静态如果表的每个字段的数据类型的定义都是使用静态的(如char),mysql就会自动使用静态MyISAM格式,这种类型格式的表的性能是很高的,也就是查询更新用的时间很少,但要知道这是在牺牲空间为代价。因为每一列都要分配最大的空间,即使有部分空间没有用到,这就使得静态的表所占的空间会比较大。2、MyISAM动态如果表的每个字段的数据类型的定义都是使用动态的(如varchar),mysql就会自动使用动态MyISAM格式,这种类型格式的表的性能会有所下降,但是它的空间占有要比静态的少很多。3、MyISAM压缩如果有一张表在设计之初只赋予了它读的使命,就可以用MyISAM压缩表,在相同的配置下,它的性能是最快的。二、InnoDBInnoDB是一个事务型存储引擎,它默认支持事务。因此,在对数据完整度有较高要求的项目中,都是采用InnoDB作为存储引擎,比如跟银行相关的项目。InnoDB还引入行级锁定。其他表类型都是全表锁定,意思就是说,在一个用户要修改一张表中,自己那一行的某个信息的时候,数据库会先锁定整张表,其他用户对这张表无法进行操作,这就是全表锁定。行级锁定就不一样了,只锁定自己要修改的那一行的,也就是说其他人对表还可以进行操作,只是不能操作被锁定的那一行的数据了。好处显而易见,在速度上更快了,特别适合处理多重并发的更新请求。InnoDB还引入了外键约束。
上滑加载中
推荐直播
-
华为云码道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华为软件挑战赛冠军
高手来了:看软挑高手解析二维排样问题—从工业难题到算法突破
回顾中
热门标签