第13章SQL语句语法

目录

13.1数据定义语句
13.1.1原子数据定义语句支持
13.1.2 ALTER DATABASE语法
13.1.3 ALTER EVENT语法
13.1.4 ALTER FUNCTION语法
13.1.5 ALTER INSTANCE语法
13.1.6 ALTER LOGFILE GROUP语法
13.1.7更改过程语法
13.1.8 ALTER SERVER语法
13.1.9 ALTER TABLE语法
13.1.10 ALTER TABLESPACE语法
13.1.11 ALTER VIEW语法
13.1.12 CREATE DATABASE语法
13.1.13 CREATE EVENT语法
13.1.14 CREATE FUNCTION语法
13.1.15 CREATE INDEX语法
13.1.16 CREATE LOGFILE GROUP语法
13.1.17创建过程和创建函数语法
13.1.18 CREATE SERVER语法
13.1.19创建空间参考系统语法
13.1.20 CREATE TABLE语法
13.1.21 CREATE TABLESPACE语法
13.1.22 CREATE TRIGGER语法
13.1.23创建视图语法
13.1.24 DROP DATABASE语法
13.1.25 DROP EVENT语法
13.1.26 DROP FUNCTION语法
13.1.27 DROP INDEX语法
13.1.28 DROP LOGFILE GROUP语法
13.1.29 DROP PROCEDURE和DROP FUNCTION语法
13.1.30 DROP SERVER语法
13.1.31 DROP空间参考系统语法
13.1.32 DROP TABLE语法
13.1.33 DROP TABLESPACE语法
13.1.34 DROP TRIGGER语法
13.1.35 DROP VIEW语法
13.1.36 RENAME TABLE语法
13.1.37 TRUNCATE TABLE语法
13.2数据处理语句
13.2.1 CALL语法
13.2.2 DELETE语法
13.2.3 DO语法
13.2.4 HANDLER语法
13.2.5 IMPORT TABLE语法
13.2.6 INSERT语法
13.2.7 LOAD DATA语法
13.2.8 LOAD XML语法
13.2.9 REPLACE语法
13.2.10 SELECT语法
13.2.11子查询语法
13.2.12 UPDATE语法
13.2.13 WITH语法(公用表表达式)
13.3交易和锁定声明
13.3.1 START TRANSACTION,COMMIT和ROLLBACK语法
13.3.2无法回滚的陈述
13.3.3导致隐式提交的语句
13.3.4 SAVEPOINT,ROLLBACK到SAVEPOINT和RELEASE SAVEPOINT语法
13.3.5备份和解锁实例的锁定实例语法
13.3.6 LOCK TABLES和UNLOCK TABLES语法
13.3.7 SET TRANSACTION语法
13.3.8 XA交易
13.4复制语句
13.4.1控制主服务器的SQL语句
13.4.2用于控制从属服务器的SQL语句
13.4.3用于控制组复制的SQL语句
13.5准备好的SQL语句语法
13.5.1 PREPARE语法
13.5.2 EXECUTE语法
13.5.3 DEALLOCATE PREPARE语法
13.6复合语句语法
13.6.1 BEGIN ... END复合语句语法
13.6.2语句标签语法
13.6.3 DECLARE语法
13.6.4存储程序中的变量
13.6.5流量控制声明
13.6.6游标
13.6.7条件处理
13.7数据库管理声明
13.7.1账户管理声明
13.7.2资源组管理声明
13.7.3表维护声明
13.7.4组件,插件和用户定义的功能语句
13.7.5 SET语法
13.7.6 SHOW语法
13.7.7其他行政声明
13.8效用声明
13.8.1 DESCRIBE语法
13.8.2 EXPLAIN语法
13.8.3 HELP语法
13.8.4 USE语法

本章介绍 MySQL支持 SQL 语句 的语法

13.1数据定义语句

13.1.1原子数据定义语句支持

MySQL 8.0支持原子数据定义语言(DDL)语句。 此功能称为 原子DDL 原子DDL语句将与DDL操作关联的数据字典更新,存储引擎操作和二进制日志写入组合到单个原子事务中。 即使服务器在操作期间停止,也会提交事务,并将适用的更改保留到数据字典,存储引擎和二进制日志中,或者回滚事务。

通过在MySQL 8.0中引入MySQL数据字典,可以实现Atomic DDL。 在早期的MySQL版本中,元数据存储在元数据文件,非事务性表和存储引擎特定的字典中,这需要中间提交。 MySQL数据字典提供的集中式事务元数据存储消除了这一障碍,使得将DDL语句操作重组为原子事务成为可能。

原子DDL功能在本节的以下主题中描述:

支持的DDL语句

原子DDL功能支持表和非表DDL语句。 与表相关的DDL操作需要存储引擎支持,而非表DDL操作则不需要。 目前,只有 InnoDB 存储引擎支持原子DDL。

  • 受支持的表DDL语句包括 CREATE ALTER DROP 对数据库,表,表和索引,以及语句 TRUNCATE TABLE 声明。

  • 支持的非表DDL语句包括:

    • CREATE DROP 语句,以及(如果适用) ALTER 存储程序,触发器,视图和用户定义函数(UDF)的语句。

    • 账户管理语句: CREATE ALTER DROP ,,如果适用, RENAME 报表用户和角色,以及 GRANT REVOKE 报表。

原子DDL功能不支持以下语句:

原子DDL特性

原子DDL语句的特征包括以下内容:

  • 元数据更新,二进制日志写入和存储引擎操作(如果适用)将合并为单个事务。

  • 在DDL操作期间,SQL层没有中间提交。

  • 适用时:

    • 数据字典,例程,事件和UDF高速缓存的状态与DDL操作的状态一致,这意味着更新高速缓存以反映DDL操作是成功完成还是回滚。

    • DDL操作中涉及的存储引擎方法不执行中间提交,并且存储引擎将自身注册为DDL事务的一部分。

    • 存储引擎支持DDL操作的重做和回滚,这在DDL操作的 Post-DDL 阶段执行。

  • DDL操作的可见行为是原子的,这会更改某些DDL语句的行为。 请参阅 DDL语句行为中的更改

注意

原子或其他DDL语句隐式结束当前会话中处于活动状态的任何事务,就好像您 COMMIT 在执行语句之前 完成了 一样。 这意味着DDL语句不能在另一个事务中,在事务控制语句中执行 START TRANSACTION ... COMMIT ,或者与同一事务中的其他语句结合使用。

DDL语句行为的变化

本节介绍由于引入原子DDL支持而导致的DDL语句行为的更改。

  • DROP TABLE 如果所有命名表都使用原子DDL支持的存储引擎,则操作是完全原子的。 该语句要么成功删除所有表,要么回滚。

    DROP TABLE 如果命名表不存在,并且未进行任何更改(无论存储引擎如何),则会失败并显示错误。 以下示例演示了此行为更改,其中 DROP TABLE 语句失败,因为命名表不存在:

    mysql> CREATE TABLE t1 (c1 INT);
    mysql>DROP TABLE t1, t2;
    ERROR 1051(42S02):未知表'test.t2'
    MySQL的> SHOW TABLES;
    + ---------------- +
    | Tables_in_test |
    + ---------------- +
    | t1 |
    + ---------------- +
    

    在引入原子DDL之前, DROP TABLE 报告指定表的错误,该错误不存在但成功存在于已存在的命名表中:

    mysql> CREATE TABLE t1 (c1 INT);
    mysql>DROP TABLE t1, t2;
    ERROR 1051(42S02):未知表'test.t2'
    MySQL的> SHOW TABLES;
    空集(0.00秒)
    
    注意

    由于行为的这种变化, DROP TABLE MySQL 5.7主服务器上 的部分完成 语句在MySQL 8.0从服务器上复制时失败。 要避免此故障情形,请 IF EXISTS DROP TABLE 语句中 使用 语法 以防止对不存在的表发生错误。

  • DROP DATABASE 如果所有表都使用原子DDL支持的存储引擎,则为atomic。 该语句要么成功删除所有对象,要么回滚。 但是,从文件系统中删除数据库目录最后发生,并且不是原子事务的一部分。 如果由于文件系统错误或服务器暂停而导致数据库目录的删除失败, DROP DATABASE 则不会回滚事务。

  • 对于不使用原子DDL支持的存储引擎的表,表删除发生在原子 DROP TABLE DROP DATABASE 事务之外。 这样的表删除被单独写入二进制日志,这在中断 DROP TABLE DROP DATABASE 操作 的情况下将存储引擎,数据字典和二进制日志之间的差异限制为最多一个表 对于删除多个表的操作,不使用原子DDL支持的存储引擎的表将在执行之前删除。

  • CREATE TABLE ALTER TABLE RENAME TABLE TRUNCATE TABLE CREATE TABLESPACE ,和 DROP TABLESPACE 对使用原子DDL支持的存储引擎表执行的操作要么完全提交或如果服务器的操作时停止回滚。 在早期的MySQL版本中,这些操作的中断可能会导致存储引擎,数据字典和二进制日志之间的差异,或者留下孤立文件。 RENAME TABLE 如果所有命名表都使用原子DDL支持的存储引擎,则操作只是原子操作。

  • DROP VIEW 如果命名视图不存在且未进行任何更改,则会失败。 在此示例中演示了行为更改,其中 DROP VIEW 语句失败,因为命名视图不存在:

    mysql> CREATE VIEW test.viewA AS SELECT * FROM t;
    mysql>DROP VIEW test.viewA, test.viewB;
    ERROR 1051(42S02):未知表'test.viewB'
    MySQL的> SHOW FULL TABLES IN test WHERE TABLE_TYPE LIKE 'VIEW';
    + ---------------- + ------------ +
    | Tables_in_test | Table_type |
    + ---------------- + ------------ +
    | viewA | 查看|
    + ---------------- + ------------ +
    

    在引入原子DDL之前, DROP VIEW 为命名视图返回一个错误,该错误不存在但成功存在于存在的命名视图中:

    mysql> CREATE VIEW test.viewA AS SELECT * FROM t;
    mysql>DROP VIEW test.viewA, test.viewB;
    ERROR 1051(42S02):未知表'test.viewB'
    MySQL的> SHOW FULL TABLES IN test WHERE TABLE_TYPE LIKE 'VIEW';
    空集(0.00秒)
    
    注意

    由于行为的这种变化, DROP VIEW MySQL 5.7主服务器上 的部分完成 操作在MySQL 8.0从服务器上复制时失败。 要避免此故障情形,请 IF EXISTS DROP VIEW 语句中 使用 语法 以防止对不存在的视图发生错误。

  • 不再允许部分执行帐户管理声明。 帐户管理语句对所有命名用户成功或回滚,如果发生错误则无效。 在早期的MySQL版本中,为多个用户命名的帐户管理语句可能对某些用户成功,而对其他用户则失败。

    在此示例中演示了行为更改,其中第二个 CREATE USER 语句返回错误但失败,因为它无法对所有命名用户成功。

    mysql> CREATE USER userA;
    mysql>CREATE USER userA, userB;
    ERROR 1396(HY000):'userA'@'%'的操作CREATE USER失败
    MySQL的> SELECT User FROM mysql.user WHERE User LIKE 'user%';
    + ------- +
    | 用户|
    + ------- +
    | userA |
    + ------- +
    

    在引入原子DDL之前,第二个 CREATE USER 语句为命名用户返回一个错误,该错误不存在但成功存在的命名用户:

    mysql> CREATE USER userA;
    mysql>CREATE USER userA, userB;
    ERROR 1396(HY000):'userA'@'%'的操作CREATE USER失败
    MySQL的> SELECT User FROM mysql.user WHERE User LIKE 'user%';
    + ------- +
    | 用户|
    + ------- +
    | userA |
    | userB |
    + ------- +
    
    注意

    由于行为的这种变化,MySQL 5.7主服务器上部分完成的帐户管理语句在MySQL 8.0从服务器上复制时会失败。 要避免此故障情形,请 在帐户管理语句中 使用 IF EXISTS IF NOT EXISTS 语法,以防止与命名用户相关的错误。

存储引擎支持

目前,只有 InnoDB 存储引擎支持原子DDL。 不支持原子DDL的存储引擎免于DDL原子性。 涉及豁免存储引擎的DDL操作仍然能够引入操作中断或仅部分完成时可能发生的不一致。

要支持重做和回滚DDL操作, InnoDB 请将DDL日志写入 mysql.innodb_ddl_log 表,该表是驻留在 mysql.ibd 数据字典表空间 中的隐藏数据字典表

mysql.innodb_ddl_log 在DDL操作期间 查看写入 表的 DDL日志 ,请启用 innodb_print_ddl_logs 配置选项。 有关更多信息,请参阅 查看DDL日志

注意

mysql.innodb_ddl_log 无论 innodb_flush_log_at_trx_commit 设置 如何,对表的 更改的重做日志 都会立即刷新到磁盘 立即刷新重做日志可以避免DDL操作修改数据文件的情况,但是 mysql.innodb_ddl_log 由这些操作产生的 表的 更改的重做日志 不会持久保存到磁盘。 这种情况可能会在回滚或恢复期间导致错误。

InnoDB 存储引擎分阶段执行DDL操作。 DDL操作 ALTER TABLE 可以 Commit 阶段 之前多次 执行 Prepare Perform 阶段

  1. 准备 :创建所需对象并将DDL日志写入 mysql.innodb_ddl_log 表中。 DDL日志定义了如何前滚和回滚DDL操作。

  2. 执行 :执行DDL操作。 例如,为 CREATE TABLE 操作 执行创建例程

  3. 提交 :更新数据字典并提交数据字典事务。

  4. Post-DDL :重播并从 mysql.innodb_ddl_log 表中 删除DDL日志 为了确保可以安全地执行回滚而不引入不一致,在最后阶段执行文件操作,例如重命名或删除数据文件。 这一阶段还从删除的动态元数据 mysql.innodb_dynamic_metadata 的数据字典表 DROP TABLE TRUNCATE TABLE 和该重建表其他DDL操作。

无论事务是提交还是回滚, DDL日志都会 mysql.innodb_ddl_log Post-DDL 阶段 重播并从 表中 删除 mysql.innodb_ddl_log 如果服务器在DDL操作期间暂停,则 DDL日志应仅保留在 表中。 在这种情况下,DDL日志将在恢复后重播并删除。

在恢复情况下,可以在重新启动服务器时提交或回滚DDL事务。 如果 在重做日志和二进制日志中存在DDL操作 提交 阶段 期间执行的数据字典事务,则 该操作被视为成功并且前滚。 否则,在 InnoDB 重放数据字典重做日志 时回滚不完整的数据字典事务 ,并回滚DDL事务。

查看DDL日志

mysql.innodb_ddl_log 在涉及 InnoDB 存储引擎的 原子DDL操作期间 查看写入 数据字典表 innodb_print_ddl_logs 的DDL日志 ,请启用 MySQL以将DDL日志写入 stderr 根据主机操作系统和MySQL配置, stderr 可能是错误日志,终端或控制台窗口。 请参见 第5.4.2.2节“默认错误日志目标配置”

InnoDB 将DDL日志写入 mysql.innodb_ddl_log 表以支持重做和回滚DDL操作。 mysql.innodb_ddl_log 表是隐藏在 mysql.ibd 数据字典表空间 中的隐藏数据字典表 与其他隐藏数据字典表一样, mysql.innodb_ddl_log 在非调试版本的MySQL中无法直接访问 表。 (请参见 第14.1节“数据字典模式” 。) mysql.innodb_ddl_log 的结构 对应于此定义:

CREATE TABLE mysql.innodb_ddl_log(
  id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  thread_id BIGINT UNSIGNED NOT NULL,
  类型INT UNSIGNED NOT NULL,
  space_id INT UNSIGNED,
  page_no INT未签名,
  index_id BIGINT UNSIGNED,
  table_id BIGINT UNSIGNED,
  old_file_path VARCHAR(512)COLLATE UTF8_BIN,
  new_file_path VARCHAR(512)COLLATE UTF8_BIN,
  KEY(thread_id单)
);
  • id :DDL日志记录的唯一标识符。

  • thread_id :为每个DDL日志记录分配一个 thread_id ,用于重播和删除属于特定DDL事务的DDL日志。 涉及多个数据文件操作的DDL事务会生成多个DDL日志记录。

  • type :DDL操作类型。 类型包括 FREE (删除索引树), DELETE (删除文件), RENAME (重命名文件)或 DROP (从 mysql.innodb_dynamic_metadata 数据字典表中 删除元 数据)。

  • space_id :表空间ID。

  • page_no :包含分配信息的页面; 例如,索引树根页面。

  • index_id :索引ID。

  • table_id :表ID。

  • old_file_path :旧的表空间文件路径。 由创建或删除表空间文件的DDL操作使用; 也用于重命名表空间的DDL操作。

  • new_file_path :新的表空间文件路径。 由重命名表空间文件的DDL操作使用。

此示例演示 innodb_print_ddl_logs 如何查看 strderr CREATE TABLE 操作 写入的DDL日志

mysql> SET GLOBAL innodb_print_ddl_logs = 1;
mysql> CREATE TABLE t1(c1 INT)ENGINE = InnoDB;
[注意] [000000] InnoDB:DDL日志插入:[DDL记录:DELETE SPACE,id = 18,thread_id = 7, 
space_id = 5,old_file_path =。/ test / t1.ibd]
[注意] [000000] InnoDB:DDL日志删除:按id 18
[注意] [000000] InnoDB:DDL日志插入:[DDL记录:REMOVE CACHE,id = 19,thread_id = 7, 
table_id = 1058,new_file_path = test / t1]
[注意] [000000] InnoDB:DDL日志删除:按id 19
[注意] [000000] InnoDB:DDL日志插入:[DDL记录:FREE,id = 20,thread_id = 7, 
space_id = 5,index_id = 132,page_no = 4]
[注意] [000000] InnoDB:DDL日志删除:按id 20
[注意] [000000] InnoDB:DDL log post ddl:begin for thread id:7
[注意] [000000] InnoDB:DDL日志发布ddl:end for thread id:7

13.1.2 ALTER DATABASE语法

ALTER {DATABASE | SCHEMA} [ db_name]
     alter_specification......

alter_specification
    [DEFAULT] CHARACTER SET [=] charset_name
  | [DEFAULT] COLLATE [=]collation_name
  | DEFAULT ENCRYPTION [=] {'Y'| 'N'}

ALTER DATABASE 使您可以更改数据库的整体特征。 这些特征存储在数据字典中。 要使用 ALTER DATABASE ,您需要 ALTER 数据库 权限。 ALTER SCHEMA 是...的同义词 ALTER DATABASE

可以从第一个语法中省略数据库名称,在这种情况下,该语句将应用于默认数据库。

国家语言特色

CHARACTER SET 子句更改默认数据库字符集。 COLLATE 子句更改默认数据库排序规则。 第10章, 字符集,排序规则,Unicode ,讨论字符集和排序规则名称。

您可以分别使用 SHOW CHARACTER SET SHOW COLLATION 语句 查看可用的字符集和排序规则 有关更多 信息, 请参见 第13.7.6.3节“显示字符集语法” 第13.7.6.4 节“显示字符集语法”

如果更改数据库的默认字符集或排序规则,则必须删除并重新创建使用数据库默认值的存储例程,以便它们使用新的默认值。 (在存储例程中,如果未明确指定字符集或排序规则,则具有字符数据类型的变量将使用数据库缺省值。请参见 第13.1.17节“创建过程和创建函数语法” 。)

加密

DEFAULT ENCRYPTION MySQL 8.0.16中引入的 子句定义了默认数据库加密,该加密由数据库中创建的表继承。 更改数据库的默认加密不会更改与架构关联的现有表的加密。 只有新创建的表才会继承默认的数据库加密。 ALTER DATABASE 没有 DEFAULT ENCRYPTION 子句的情况下 执行的 语句会保留现有的默认数据库加密。 如果 table_encryption_privilege_check 启用 变量, TABLE_ENCRYPTION_ADMIN 则需要 权限才能指定与设置不同的默认加密 default_table_encryption 设置。 有关更多信息,请参阅 为架构和常规表空间定义加密默认值

13.1.3 ALTER EVENT语法

改变
    [DEFINER = user]
    活动event_name
    [安排时间表schedule]
    [完成[NOT] PRESERVE]
    [重命名new_event_name]
    [ENABLE | 禁用| 禁止在[SLAVE]
    [评论' string']
    [DO event_body]

ALTER EVENT 语句更改现有事件的一个或多个特征,而无需删除和重新创建它。 的语法的每个的 DEFINER ON SCHEDULE ON COMPLETION COMMENT ENABLE / DISABLE ,和 DO 条款是完全一样的当用于如 CREATE EVENT (请参见 第13.1.13节“创建事件语法” 。)

任何用户都可以更改在该用户具有该 EVENT 权限 的数据库上定义的事件 当用户执行成功的 ALTER EVENT 语句时,该用户将成为受影响事件的定义者。

ALTER EVENT 仅适用于现有事件:

的MySQL> ALTER EVENT no_such_event 
     >      ON SCHEDULE 
     >        ERROR 1517(HY000):未知事件'no_such_event'EVERY '2:3' DAY_HOUR;

在以下每个示例中,假设命名事件 myevent 的定义如下所示:

创造事件myevent
    按照时间表
      每6个小时
    评论'示例评论。'
      更新myschema.mytable SET mycol = mycol + 1;

以下语句将计划 myevent 从立即开始每六小时 更改为 每十二小时一次,从语句运行开始四小时开始:

改变事件myevent
    按照时间表
      每12个小时
    STARTS CURRENT_TIMESTAMP + INTERVAL 4小时;

可以在单个语句中更改事件的多个特征。 此示例将执行的SQL语句更改为 myevent 删除所有记录的 语句 mytable ; 它还会更改事件的计划,使其在 ALTER EVENT 运行 语句 后一天执行一次

改变事件myevent
    按照时间表
      在CURRENT_TIMESTAMP + INTERVAL 1天
      TRUNCATE TABLE myschema.mytable;

ALTER EVENT 仅为要更改的特征 语句中 指定选项 ; 省略的选项保留其现有值。 这包括任何默认值 CREATE EVENT ,例如 ENABLE

要禁用 myevent ,请使用以下 ALTER EVENT 语句:

改变事件myevent
    禁用;

ON SCHEDULE 子句可以使用涉及内置MySQL函数和用户变量的表达式来获取 它包含的 任何 timestamp interval 值。 您不能在此类表达式中使用存储的例程或用户定义的函数,也不能使用任何表引用; 但是,你可以使用 SELECT FROM DUAL 对于这两个 ALTER EVENT CREATE EVENT 陈述 都是如此 在这种情况下,特别不允许引用存储例程,用户定义函数和表,并且会因错误而失败(参见Bug#22830)。

虽然 在其 子句 ALTER EVENT 中包含另一个 ALTER EVENT 语句的 DO 语句似乎成功,但是当服务器尝试执行生成的已调度事件时,执行将失败并显示错误。

要重命名事件,请使用 ALTER EVENT 语句的 RENAME TO 子句。 此语句将事件重命名 myevent yourevent

改变事件myevent
    重命名给你;

您还可以使用 ALTER EVENT ... RENAME TO ... db_name.event_name 表示法 将事件移动到其他数据库 ,如下所示:

ALTER EVENT olddb.myevent
    重命名为newdb.myevent;

要执行前一个语句,执行它的用户必须 EVENT 同时拥有 olddb newdb 数据库 权限

注意

没有 RENAME EVENT 声明。

该值 DISABLE ON SLAVE 用于复制从站而不是 ENABLE DISABLE 表示在主站上创建并复制到从站的事件,但不在从站上执行。 通常, DISABLE ON SLAVE 根据需要自动设置; 但是,在某些情况下,您可能需要或需要手动更改它。 有关 更多信息 请参见 第17.4.1.16节“调用的特性的复制”

13.1.4 ALTER FUNCTION语法

改变功能func_name[ characteristic...]

characteristic
    评论' string'
  | 语言SQL
  | {包含SQL | 没有SQL | 读取SQL数据| 修改SQL DATA}
  | SQL SECURITY {DEFINER | INVOKER}

此语句可用于更改存储函数的特征。 可以在 ALTER FUNCTION 语句中 指定多个更改 但是,您无法使用此语句更改存储函数的参数或正文; 要进行此类更改,您必须使用 DROP FUNCTION 删除并重新创建函数 CREATE FUNCTION

您必须拥有 ALTER ROUTINE 该功能 权限。 (该权限自动授予函数创建者。)如果启用了二进制日志记录,则该 ALTER FUNCTION 语句可能还需要该 SUPER 特权,如 第24.7节“存储程序二进制日志记录”中所述

13.1.5 ALTER INSTANCE语法

更改实例 instance_action

instance_action:{
    旋转INNODB MASTER KEY
  | 旋转BINLOG MASTER KEY
  | RELOAD TLS [没有错误的错误]
}

ALTER INSTANCE 定义适用于MySQL服务器实例的操作。 该声明支持以下操作:

  • ALTER INSTANCE ROTATE INNODB MASTER KEY

    此操作将旋转用于 InnoDB 表空间加密 的主加密密钥 密钥轮换需要 ENCRYPTION_KEY_ADMIN SUPER 特权。 要执行此操作,必须安装和配置密钥环插件。 有关说明,请参见 第6.4.4节“MySQL密钥环”

    ALTER INSTANCE ROTATE INNODB MASTER KEY 支持并发DML。 但是,它不能与 CREATE TABLE ... ENCRYPTION 同时 ALTER TABLE ... ENCRYPTION 运行,并且会采取锁定来防止因并发执行这些语句而引起的冲突。 如果其中一个冲突的语句正在运行,则必须先完成,然后才能继续。

    ALTER INSTANCE ROTATE INNODB MASTER KEY 语句将写入二进制日志,以便它们可以在复制的服务器上执行。

    有关其他 ALTER INSTANCE ROTATE INNODB MASTER KEY 用法信息,请参见 第15.6.3.9节“InnoDB静态数据加密”

  • ALTER INSTANCE ROTATE BINLOG MASTER KEY

    此操作将旋转用于二进制日志加密的二进制日志主密钥。 二进制日志主密钥的密钥轮换需要 BINLOG_ENCRYPTION_ADMIN SUPER 特权。 如果 binlog_encryption 系统变量设置为, 则不能使用该语句 OFF 要执行此操作,必须安装和配置密钥环插件。 有关说明,请参见 第6.4.4节“MySQL密钥环”

    ALTER INSTANCE ROTATE BINLOG MASTER KEY 操作不会写入二进制日志,也不会在复制从服务器上执行。 因此,二进制日志主密钥轮换可以在包括混合MySQL版本的复制环境中执行。 要在所有适用的主服务器和从属服务器上安排定期轮换二进制日志主密钥,可以在每台服务器上启用MySQL事件调度程序,并 ALTER INSTANCE ROTATE BINLOG MASTER KEY 使用 CREATE EVENT 语句 发出 语句。 如果您因为怀疑当前或任何以前的二进制日志主密钥可能已被泄露而轮换二进制日志主密钥,请在每个适用的主从服务器上发出该语句,这样您就可以验证是否立即符合。

    有关其他 ALTER INSTANCE ROTATE BINLOG MASTER KEY 使用信息,包括如果进程未正确完成或由于意外服务器暂停而中断操作,请参见 第17.3.10节“加密二进制日志文件和中继日志文件”

  • ALTER INSTANCE RELOAD TLS

    此操作从定义上下文的系统变量的当前值重新配置SSL上下文。 它还会更新反映活动上下文值的状态变量。 此操作需要该 CONNECTION_ADMIN 权限。

    默认情况下, RELOAD TLS 如果配置值不允许创建新的SSL上下文 ,则 操作将回滚并显示错误,并且无效。 先前的上下文值继续用于新连接。

    如果 NO ROLLBACK ON ERROR 给出 了可选 子句并且无法创建新上下文,则不会发生回滚。 而是生成警告,并为新连接禁用SSL。

    ALTER INSTANCE RELOAD TLS 语句不会写入二进制日志(因此不会被复制)。 SSL配置是本地的,取决于所有涉及的服务器上不一定存在的本地文件。

    有关重新配置SSL上下文的其他信息,包括与上下文相关的系统和状态变量,请参阅 加密连接的服务器端运行时配置

13.1.6 ALTER LOGFILE GROUP语法

ALTER LOGFILE GROUP logfile_group
    ADD UNDOFILE' file_name'
    [INITIAL_SIZE [=] size]
    [等待]
    发动机[=] engine_name

此语句将 UNDO 名为' file_name ' 文件 添加 到现有日志文件组 logfile_group 一个 ALTER LOGFILE GROUP 语句有一个且只有一个 ADD UNDOFILE 条款。 DROP UNDOFILE 目前不支持 任何 条款。

注意

所有NDB Cluster Disk Data对象共享相同的命名空间。 这意味着 必须唯一地命名 每个磁盘数据对象 (而不仅仅是给定类型的每个磁盘数据对象)。 例如,您不能拥有具有相同名称的表空间和撤消日志文件,也不能具有撤消日志文件和具有相同名称的数据文件。

可选 INITIAL_SIZE 参数设置 UNDO 文件的初始大小(以字节为单位); 如果未指定,则初始大小默认为134217728(128 MB)。 您可以选择 size 使用一个字母的缩写,一个数量级,类似于中使用的那些 my.cnf 通常,这是字母 M (兆字节)或 G (千兆字节)之一。 (Bug#13116514,Bug#16104705,Bug#62858)

在32位系统上,支持的最大值为 INITIAL_SIZE 4294967296(4 GB)。 (Bug#29186)

允许的最小值为 INITIAL_SIZE 1048576(1 MB)。 (Bug#29574)

注意

WAIT 被解析但被忽略。 此关键字目前无效,可用于将来的扩展。

ENGINE 参数(必需)确定这是由该日志文件组所使用的,与存储引擎 engine_name 是所述存储引擎的名称。 目前,唯一可接受的值 engine_name NDBCLUSTER NDB 这两个值是等价的。

下面是一个示例,它假定 lg_3 已经使用创建 了日志文件组 CREATE LOGFILE GROUP (请参见 第13.1.16节“CREATE LOGFILE GROUP语法” ):

ALTER LOGFILE GROUP lg_3
    添加UNDOFILE'under_10.dat'
    INITIAL_SIZE = 32M
    ENGINE = NDBCLUSTER;

ALTER LOGFILE GROUP ENGINE = NDBCLUSTER (替代地 ENGINE = NDB )一起使用时, UNDO 在每个NDB集群数据节点上创建日志文件。 您可以 UNDO 通过查询 INFORMATION_SCHEMA.FILES 来验证 文件是否已创建并获取有关它们的信息 例如:

mysql> SELECT FILE_NAME, LOGFILE_GROUP_NUMBER, EXTRA
    - > FROM INFORMATION_SCHEMA.FILES
    - >WHERE LOGFILE_GROUP_NAME = 'lg_3';
+ ------------- + ---------------------- + ------------ ---- +
| FILE_NAME | LOGFILE_GROUP_NUMBER | 额外|
+ ------------- + ---------------------- + ------------ ---- +
| newdata.dat | 0 | CLUSTER_NODE = 3 |
| newdata.dat | 0 | CLUSTER_NODE = 4 |
| undo_10.dat | 11 | CLUSTER_NODE = 3 |
| undo_10.dat | 11 | CLUSTER_NODE = 4 |
+ ------------- + ---------------------- + ------------ ---- +
4行(0.01秒)

(参见 第25.11节“INFORMATION_SCHEMA文件表” 。)

用于的内存 UNDO_BUFFER_SIZE 来自全局池,其大小由 SharedGlobalMemory 数据节点配置参数 的值确定 这包括通过设置 InitialLogFileGroup 数据节点配置参数 对此选项隐含的任何默认值

ALTER LOGFILE GROUP 仅适用于NDB Cluster的磁盘数据存储。 有关更多信息,请参见 第22.5.13节“NDB集群磁盘数据表”

13.1.7更改过程语法

更改程序proc_name[ characteristic...]

characteristic
    评论' string'
  | 语言SQL
  | {包含SQL | 没有SQL | 读取SQL数据| 修改SQL DATA}
  | SQL SECURITY {DEFINER | INVOKER}

此语句可用于更改存储过程的特征。 可以在 ALTER PROCEDURE 语句中 指定多个更改 但是,您无法使用此语句更改存储过程的参数或主体; 要进行此类更改,您必须使用 DROP PROCEDURE 删除并重新创建该过程 CREATE PROCEDURE

您必须拥有 ALTER ROUTINE 该过程 特权。 默认情况下,该权限自动授予过程创建者。 可以通过禁用 automatic_sp_privileges 系统变量 来更改此行为 请参见 第24.2.2节“存储例程和MySQL特权”

13.1.8 ALTER SERVER语法

更改服务器   server_name
    选项(option[,option] ...)

更改服务器信息 server_name ,调整 CREATE SERVER 语句中 允许的任何选项 mysql.servers 表中 的相应字段会相应 更新。 此声明需要该 SUPER 权限。

例如,要更新 USER 选项:

ALTER SERVER的选项(USER'sally');

ALTER SERVER 导致隐式提交。 请参见 第13.3.3节“导致隐式提交的语句”

ALTER SERVER 无论正在使用的日志记录格式如何,都不会写入二进制日志。

13.1.9 ALTER TABLE语法

ALTER TABLE tbl_name
    [ alter_specification[,alter_specification] ...]
    [ partition_options]

alter_specificationtable_options
  | 添加[栏目] 
        [第一个| 之后]col_name column_definitioncol_name
  | 添加[栏目](,...)col_name column_definition
  | 添加{INDEX | KEY} [ index_name]
        [ index_type](key_part,...)[ index_option] ......
  | ADD {FULLTEXT | SPATIAL} [INDEX | KEY] [ index_name]key_part,......)[ index_option] ......
  | 添加[CONSTRAINT [ symbol]] PRIMARY KEY
        [ index_type](key_part,...)
        [ index_option] ......
  | ADD [CONSTRAINT [ symbol]] UNIQUE [INDEX | KEY]
        [ index_name] [ index_type](key_part,...)
        [ index_option] ......
  | 添加[CONSTRAINT [ symbol]]外键
        [ index_name](col_name,...)
         reference_definition
  | ADD check_constraint_definition
  | DROP CHECK symbol
  | 更改检查symbol[NOT]强制执行
  | 算法[=] {DEFAULT | INSTANT | INPLACE | COPY}
  | ALTER [COLUMN] col_name{SET DEFAULT literal| DROP DEFAULT}
  | ALTER INDEX index_name{VISIBLE | 无形}
  | 更改[栏目] 
        [第一|后]old_col_name new_col_name column_definitioncol_name
  | [DEFAULT] CHARACTER SET [=] charset_name[COLLATE [=] collation_name]
  | 转换为字符集charset_name[COLLATE collation_name]
  | {DISABLE | ENABLE} KEYS
  | {DISCARD | IMPORT} TABLESPACE
  | DROP [COLUMN] col_name
  | DROP {INDEX | KEY}index_name
  | DROP PRIMARY KEY
  | DROP FOREIGN KEYfk_symbol
  | 
  | LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE}
  | 修改[专栏] 
        [第一个| 之后]col_name column_definitioncol_name
  | ORDER BY col_name[,col_name] ......
  | RENAME COLUMN old_col_nameTO new_col_name
  | 重命名{INDEX | KEY} old_index_namenew_index_name
  | 重命名[TO | AS]new_tbl_name
  | {WITHOUT | WITH}验证
  | 添加分区(partition_definition
  | DROP PARTITION partition_names
  | DISCARD PARTITION { partition_names| ALL} TABLESPACE
  | IMPORT PARTITION { partition_names| ALL} TABLESPACE
  | TRUNCATE PARTITION { partition_names| 所有}
  | COALESCE PARTITION number
  | 重新划分partition_namespartition_definitions
  | partition_nametbl_name[[WITH | WITHOUT}验证]的交换分区
  | 分析分区{ partition_names| 所有}
  | 检查分区{ partition_names| 所有}
  | OPTIMIZE PARTITION { partition_names| 所有}
  | REBUILD PARTITION { partition_names| 所有}
  | 修复分区{ partition_names| 所有}
  | 删除分区

key_part:{ col_name[(length)] | expr)} [ASC | DESC]

index_type
    使用{BTREE | HASH}

index_option
    KEY_BLOCK_SIZE [=] value
  | index_type
  | 与PARSER parser_name
  | 评论' string'
  | {VISIBLE | 无形}

check_constraint_definition
    [CONSTRAINT [ symbol]] CHECK(expr)[[NOT] ENFORCED]

table_optionstable_option[[,] table_option] ......

table_option
    AUTO_INCREMENT [=] value
  | AVG_ROW_LENGTH [=] value
  | [DEFAULT] CHARACTER SET [=]charset_name
  | CHECKSUM [=] {0 | 1}
  | [DEFAULT] COLLATE [=] collation_name
  | 评论[=]' string'
  | COMPRESSION [=] {'ZLIB'|'LZ4'|'NONE'}
  | 连接[=]' connect_string'
  | {DATA | INDEX} DIRECTORY [=]' absolute path to directory'
  | DELAY_KEY_WRITE [=] {0 | 1}
  | ENCRYPTION [=] {'Y'| 'N'}
  | 发动机[=]engine_name
  | INSERT_METHOD [=] {NO | 第一个| 最后}
  | KEY_BLOCK_SIZE [=] value
  | MAX_ROWS [=] value
  | MIN_ROWS [=]value
  | PACK_KEYS [=] {0 | 1 | 默认}
  | 密码[=]' string'
  | ROW_FORMAT [=] {DEFAULT | DYNAMIC | FIXED | COMPRESSED | REDUNDANT | COMPACT}
  | STATS_AUTO_RECALC [=] {DEFAULT | 0 | 1}
  | STATS_PERSISTENT [=] {DEFAULT | 0 | 1}
  | STATS_SAMPLE_PAGES [=] value
  | TABLESPACE tablespace_name[STORAGE {DISK | MEMORY}]
  | UNION [=](tbl_name[,tbl_name] ......)

partition_options
    (见CREATE TABLE选项)

ALTER TABLE 改变表的结构。 例如,您可以添加或删除列,创建或销毁索引,更改现有列的类型,或重命名列或表本身。 您还可以更改特征,例如用于表的存储引擎或表注释。

ALTER TABLE 语句 还有其他几个方面 ,本节中的以下主题对此进行了描述:

表格选项

table_options 意味着可以在可以使用的一种表选项 CREATE TABLE 语句,比如 ENGINE AUTO_INCREMENT AVG_ROW_LENGTH MAX_ROWS ROW_FORMAT ,或 TABLESPACE

有关所有表选项的说明,请参见 第13.1.20节“CREATE TABLE语法” 但是, ALTER TABLE 忽略 DATA DIRECTORY INDEX DIRECTORY 作为表选项给出。 ALTER TABLE 仅允许它们作为分区选项,并要求您拥有该 FILE 权限。

使用表选项 ALTER TABLE 提供了一种更改单个表特征的便捷方法。 例如:

  • 如果 t1 当前不是 InnoDB 表,则此语句将其存储引擎更改为 InnoDB

    ALTER TABLE t1 ENGINE = InnoDB;
    
  • 要更改 InnoDB 表以使用压缩行存储格式:

    ALTER TABLE t1 ROW_FORMAT = COMPRESSED;
    
  • ENCRYPTION 子句启用或禁用表的页级数据加密 InnoDB 必须安装密钥环插件并将其配置为启用加密。

    如果 table_encryption_privilege_check 启用 变量, TABLE_ENCRYPTION_ADMIN 则需要使用具有 ENCRYPTION 与默认架构加密设置不同的设置 子句 权限

    在MySQL 8.0.16之前, ENCRYPTION 仅在更改驻留在每个表文件表空间中的表时才支持 子句。 从MySQL 8.0.16开始, ENCRYPTION 对于驻留在一般表空间中的表也支持 子句。

    对于驻留在常规表空间中的表,表和表空间加密必须匹配。

    如果没有明确指定 ENCRYPTION 子句, 则不允许通过将表移动到不同的表空间或更改存储引擎来更改表加密

    从MySQL 8.0.16开始, 如果表使用不支持加密的存储引擎,则 指定 ENCRYPTION 一个值不是 'N' '' 不允许 子句 此前,该条款被接受。 尝试 ENCRYPTION 使用不支持加密的存储引擎在启用加密的模式中 创建没有 子句 的表 也是不允许的。

    有关更多信息,请参见 第15.6.3.9节“InnoDB静态数据加密”

  • 要重置当前的自动增量值:

    ALTER TABLE t1 AUTO_INCREMENT = 13;
    

    您无法将计数器重置为小于或等于当前正在使用的值的值。 对于两者 InnoDB MyISAM ,如果该值小于或等于 AUTO_INCREMENT 列中当前的最大值,则将该值重置为当前最大 AUTO_INCREMENT 列值加1。

  • 要更改默认表格字符集:

    ALTER TABLE t1 CHARACTER SET = utf8;
    

    另请参阅 更改字符集

  • 添加(或更改)表注释:

    ALTER TABLE t1 COMMENT ='新表评论';
    
  • ALTER TABLE TABLESPACE 选项一起 使用 InnoDB 在现有 通用表空间 每表文件表 空间和 系统表空间 之间 移动 请参阅 使用ALTER TABLE在表空间之间移动表

    • ALTER TABLE ... TABLESPACE 即使 TABLESPACE 属性未从其先前值更改, 操作也始终会导致完整表重建

    • ALTER TABLE ... TABLESPACE 语法不支持将表从临时表空间移动到持久表空间。

    • 不支持 DATA DIRECTORY 子句,但 CREATE TABLE ... TABLESPACE 不支持 子句, ALTER TABLE ... TABLESPACE 如果指定则忽略 子句

    • 有关该 TABLESPACE 选项 的功能和限制的详细信息 ,请参阅 CREATE TABLE

  • MySQL NDB Cluster 8.0支持设置 NDB_TABLE 用于控制表的分区平衡(片段计数类型),从任何副本读取,完全复制或这些的任意组合的选项,作为 ALTER TABLE 语句 的表注释的一部分 以相同的方式至于 CREATE TABLE ,如本例所示:

    ALTER TABLE t1 COMMENT =“NDB_TABLE = READ_BACKUP = 0,PARTITION_BALANCE = FOR_RA_BY_NODE”;
    

    请记住, ALTER TABLE ... COMMENT ... 丢弃该表的任何现有注释。 有关 其他信息和示例, 请参阅 设置NDB_TABLE选项

要验证表选项是否按预期更改,请使用 SHOW CREATE TABLE 或查询 INFORMATION_SCHEMA.TABLES 表。

性能和空间要求

ALTER TABLE 使用以下算法之一处理操作:

  • COPY :对原始表的副本执行操作,并将表数据从原始表逐行复制到新表。 不允许并发DML。

  • INPLACE :操作避免复制表数据,但可能会重建表。 可以在操作的准备和执行阶段期间简要地对表进行独占元数据锁定。 通常,支持并发DML。

  • INSTANT :操作仅修改数据字典中的元数据。 在准备和执行期间,不会在表上采用独占元数据锁,并且表数据不受影响,从而使操作立即生效。 允许并发DML。 (在MySQL 8.0.12中引入)

ALGORITHM 条款是可选的。 如果 ALGORITHM 省略 子句,MySQL将使用 支持它的 ALGORITHM=INSTANT 存储引擎和 ALTER TABLE 子句。 否则, ALGORITHM=INPLACE 使用。 如果 ALGORITHM=INPLACE 不支持, ALGORITHM=COPY 则使用。

指定 ALGORITHM 子句需要操作将指定的算法用于支持它的子句和存储引擎,否则将失败并返回错误。 指定 ALGORITHM=DEFAULT 与省略该 ALGORITHM 子句 相同

ALTER TABLE 使用该 COPY 算法的操作等待修改表的其他操作完成。 对表副本应用更改后,将复制数据,删除原始表,并将表副本重命名为原始表的名称。 ALTER TABLE 执行操作时,原始表可由其他会话读取(不久之后会注明)。 ALTER TABLE 操作开始 后启动的表的更新和写入将 停止,直到新表准备就绪,然后自动重定向到新表。 除非是a,否则表的临时副本将在原始表的数据库目录中创建 RENAME TO 将表移动到驻留在不同目录中的数据库的操作。

前面提到的异常是 ALTER TABLE 块在准备从表和表定义高速缓存中清除过时的表结构时读取(而不仅仅是写入)。 此时,它必须获得独占锁。 为此,它等待当前读者完成,并阻止新的读写。

ALTER TABLE 使用该 COPY 算法 操作 可防止并发DML操作。 仍然允许并发查询。 也就是说,表复制操作总是至少包括 LOCK=SHARED (允许查询但不是DML) 的并发限制 您可以 LOCK 通过指定 进一步限制支持该 子句的 操作的并发性 LOCK=EXCLUSIVE ,从而阻止DML和查询。 有关更多信息,请参阅 并发控制

要强制将 COPY 算法用于 ALTER TABLE 不使用 算法的 操作,请指定 ALGORITHM=COPY 或启用 old_alter_table 系统变量。 如果 old_alter_table 设置与 ALGORITHM 具有非其他值 子句 之间存在冲突 DEFAULT ,则该 ALGORITHM 子句优先。

对于 InnoDB 表, 在驻留在 共享表空间中 的表上 ALTER TABLE 使用该 COPY 算法 操作 可以增加 空间使用的空间量。 此类操作需要与表中的数据和索引一样多的额外空间。 对于驻留在共享表空间中的表,操作期间使用的额外空间不会释放回操作系统,因为它是驻留在 每个表文件表 空间中的表。

有关在线DDL操作的空间要求的信息,请参见 第15.12.3节“在线DDL空间要求”

ALTER TABLE 支持该 INPLACE 算法的 操作 包括:

  • ALTER TABLE InnoDB 在线DDL 功能 支持的操作 请参见 第15.12.1节“在线DDL操作”

  • 重命名表格。 MySQL重命名与表对应的文件 tbl_name 而不进行复制。 (您也可以使用该 RENAME TABLE 语句重命名表。请参见 第13.1.36节“RENAME TABLE语法” 。)专门为重命名表授予的权限不会迁移到新名称。 必须手动更改它们。

  • 仅修改表元数据的操作。 这些操作是立即的,因为服务器不接触表内容。 仅元数据操作包括:

    • 重命名列。

    • 更改列的默认值( NDB 除外 )。

    • 通过将新枚举或集成员添加到 有效成员值列表 末尾 修改 ENUM SET 的定义 ,只要数据类型的存储大小不会更改。 例如,将成员添加到 具有8个成员 列会将每个值所需的存储空间从1个字节更改为2个字节; 这需要一个表副本。 在列表中间添加成员会导致重新编号现有成员,这需要表副本。 SET

    • 更改空间列的定义以删除该 SRID 属性。 (添加或更改 SRID 属性确实需要重建,并且无法在适当的位置完成,因为服务器必须验证所有值都具有指定的SRID值。)

    • 从MySQL 8.0.14开始,在这些条件适用时更改列字符集:

      • 列数据类型是 CHAR VARCHAR ,一个 TEXT 类型,或 ENUM

      • 该字符集的变化是来自 utf8mb3 utf8mb4 ,或任何字符集 binary

      • 列上没有索引。

    • 从MySQL 8.0.14开始,在适用这些条件时更改生成的列:

      • 对于 InnoDB 表,修改生成的存储列但不更改其类型,表达式或可为空性的语句。

      • 对于非 InnoDB 表,修改生成的存储列或虚拟列但不更改其类型,表达式或可为空性的语句。

      An example of such a change is a change to the column comment.

  • Renaming an index.

  • Adding or dropping a secondary index, for InnoDB and NDB tables. See Section 15.12.1, “Online DDL Operations”.

  • For NDB tables, operations that add and drop indexes on variable-width columns. These operations occur online, without table copying and without blocking concurrent DML actions for most of their duration. See Section 22.5.14, “Online Operations with ALTER TABLE in NDB Cluster”.

  • Modifying index visibility with an ALTER INDEX operation.

  • Column modifications of tables containing generated columns that depend on columns with a DEFAULT value if the modified columns are not involved in the generated column expressions. For example, changing the NULL property of a separate column can be done in place without a table rebuild.

ALTER TABLE operations that support the INSTANT algorithm include:

  • Adding a column. This feature is referred to as Instant ADD COLUMN. Limitations apply. See Section 15.12.1, “Online DDL Operations”.

  • Adding or dropping a virtual column.

  • Adding or dropping a column default value.

  • Modifying the definition of an ENUM or SET column. The same restrictions apply as described above for ALGORITHM=INSTANT.

  • Changing the index type.

  • Renaming a table. The same restrictions apply as described above for ALGORITHM=INSTANT.

For more information about operations that support ALGORITHM=INSTANT, see Section 15.12.1, “Online DDL Operations”.

ALTER TABLE upgrades MySQL 5.5 temporal columns to 5.6 format for ADD COLUMN, CHANGE COLUMN, MODIFY COLUMN, ADD INDEX, and FORCE operations. This conversion cannot be done using the INPLACE algorithm because the table must be rebuilt, so specifying ALGORITHM=INPLACE in these cases results in an error. Specify ALGORITHM=COPY if necessary.

If an ALTER TABLE operation on a multicolumn index used to partition a table by KEY changes the order of the columns, it can only be performed using ALGORITHM=COPY.

The WITHOUT VALIDATION and WITH VALIDATION clauses affect whether ALTER TABLE performs an in-place operation for virtual generated column modifications. See Section 13.1.9.2, “ALTER TABLE and Generated Columns”.

NDB Cluster 8.0 supports online operations using the same ALGORITHM=INPLACE syntax used with the standard MySQL Server. See Section 22.5.14, “Online Operations with ALTER TABLE in NDB Cluster”, for more information.

ALTER TABLE with DISCARD ... PARTITION ... TABLESPACE or IMPORT ... PARTITION ... TABLESPACE does not create any temporary tables or temporary partition files.

ALTER TABLE with ADD PARTITION, DROP PARTITION, COALESCE PARTITION, REBUILD PARTITION, or REORGANIZE PARTITION does not create temporary tables (except when used with NDB tables); however, these operations can and do create temporary partition files.

ADD or DROP operations for RANGE or LIST partitions are immediate operations or nearly so. ADD or COALESCE operations for HASH or KEY partitions copy data between all partitions, unless LINEAR HASH or LINEAR KEY was used; this is effectively the same as creating a new table, although the ADD or COALESCE operation is performed partition by partition. REORGANIZE operations copy only changed partitions and do not touch unchanged ones.

For MyISAM tables, you can speed up index re-creation (the slowest part of the alteration process) by setting the myisam_sort_buffer_size system variable to a high value.

Concurrency Control

For ALTER TABLE operations that support it, you can use the LOCK clause to control the level of concurrent reads and writes on a table while it is being altered. Specifying a non-default value for this clause enables you to require a certain amount of concurrent access or exclusivity during the alter operation, and halts the operation if the requested degree of locking is not available.

Only LOCK = DEFAULT is permitted for operations that use ALGORITHM=INSTANT. The other LOCK clause parameters are not applicable.

The parameters for the LOCK clause are:

  • LOCK = DEFAULT
    

    Maximum level of concurrency for the given ALGORITHM clause (if any) and ALTER TABLE operation: Permit concurrent reads and writes if supported. If not, permit concurrent reads if supported. If not, enforce exclusive access.

  • LOCK = NONE
    

    If supported, permit concurrent reads and writes. Otherwise, an error occurs.

  • LOCK = SHARED
    

    If supported, permit concurrent reads but block writes. Writes are blocked even if concurrent writes are supported by the storage engine for the given ALGORITHM clause (if any) and ALTER TABLE operation. If concurrent reads are not supported, an error occurs.

  • LOCK = EXCLUSIVE
    

    实施独家访问。 即使存储引擎支持给定 ALGORITHM 子句(如果有)和 ALTER TABLE 操作的 并发读/写,也会执行此 操作。

添加和删​​除列

用于 ADD 向表中添加新列,以及 DROP 删除现有列。 是标准SQL的MySQL扩展。 DROP col_name

要在表格行中的特定位置添加列,请使用 FIRST 默认是最后添加列。 AFTER col_name

如果表只包含一列,则无法删除该列。 如果您打算删除表,请改用该 DROP TABLE 语句。

如果从表中删除列,则列也将从它们所属的任何索引中删除。 如果删除构成索引的所有列,则也会删除索引。 如果使用 CHANGE MODIFY 缩短列上存在索引的列,并且结果列长度小于索引长度,MySQL会自动缩短索引。

对于 ALTER TABLE ... ADD ,如果列具有使用非确定性函数的表达式默认值,则该语句可能会产生警告或错误。 有关详细信息,请参见 第17.1.3.6节“使用GTID进行复制的限制”

重命名,重新定义和重新排序列

CHANGE MODIFY RENAME COLUMN ,和 ALTER 条款允许的名称和现有列的定义被改变。 它们具有以下比较特征:

  • CHANGE

    • 可以重命名列并更改其定义,或两者。

    • 具有比 MODIFY 更多的能力 RENAME COLUMN ,但是以某些操作的便利性为代价。 CHANGE 如果不重命名,则需要将列命名两次,如果仅重命名,则需要重新指定列定义。

    • 使用 FIRST AFTER 可以重新排序列。

  • MODIFY

    • 可以更改列定义但不能更改其名称。

    • CHANGE 不更改列定义更改列定义 更方便

    • 使用 FIRST AFTER 可以重新排序列。

  • RENAME COLUMN

    • 可以更改列名但不能更改其定义。

    • 比重 CHANGE 命名列而不更改其定义 更方便

  • ALTER :仅用于更改列默认值。

CHANGE 是标准SQL的MySQL扩展。 MODIFY 并且 RENAME COLUMN 是Oracle兼容性的MySQL扩展。

要更改列以更改其名称和定义,请使用 CHANGE ,指定旧名称和新名称以及新定义。 例如,重命名 INT NOT NULL 从塔 a b 并改变其定义为使用 BIGINT 的数据类型,同时保留 NOT NULL 属性,操作如下:

ALTER TABLE t1 CHANGE ab BIGINT NOT NULL;

要更改列定义但不更改其名称,请使用 CHANGE MODIFY 使用时 CHANGE ,语法需要两个列名,因此必须指定两次相同的名称才能保持名称不变。 例如,要更改列的定义 b ,请执行以下操作:

ALTER TABLE t1 CHANGE bb INT NOT NULL;

MODIFY 更改定义而不更改名称更方便,因为它只需要列名称一次:

ALTER TABLE t1 MODIFY b INT NOT NULL;

要更改列名但不更改其定义,请使用 CHANGE RENAME COLUMN 使用时 CHANGE ,语法需要列定义,因此要保持定义不变,必须重新指定列当前具有的定义。 例如,要重命名 INT NOT NULL 的列 b a ,这样做:

ALTER TABLE t1 CHANGE ba INT NOT NULL;

RENAME COLUMN 更改名称而不更改定义更方便,因为它只需要旧名称和新名称:

ALTER TABLE t1 RENAME COLUMN b TO a;

通常,您不能将列重命名为表中已存在的名称。 但是,有时情况并非如此,例如当您交换名称或将其移动一个循环时。 如果表具有名为 a ,, b 和的 c ,则这些是有效的操作:

- 交换a和b
ALTER TABLE t1 RENAME COLUMN a TO b,
               RENAME COLUMN b TO a;
- 通过循环“旋转”a,b,c
ALTER TABLE t1 RENAME COLUMN a TO b,
               RENAME COLUMN b TO c,
               RENAME COLUMN c TO a;

对于使用 CHANGE 或的 列定义更改 MODIFY ,定义必须包括应该应用于新列的数据类型和所有属性,而不是索引属性(如 PRIMARY KEY 或) UNIQUE 原始定义中存在但未为新定义指定的属性不会继续使用。 假设列 col1 被定义为 INT UNSIGNED DEFAULT 1 COMMENT 'my column' ,您按如下方式修改列,打算仅更改 INT BIGINT

ALTER TABLE t1 MODIFY col1 BIGINT;

这种说法从改变数据类型 INT BIGINT ,但它也下降了 UNSIGNED DEFAULT COMMENT 属性。 为了保留它们,声明必须明确包含它们:

ALTER TABLE t1 MODIFY col1 BIGINT UNSIGNED DEFAULT 1 COMMENT'my column';

对于使用 CHANGE 或的 数据类型更改 MODIFY ,MySQL尝试尽可能将现有列值转换为新类型。

警告

此转换可能导致数据更改。 例如,如果缩短字符串列,则可能会截断值。 要防止操作成功,如果转换为新数据类型会导致数据丢失, ALTER TABLE 在使用前启用严格SQL模式 (请参见 第5.1.11节“服务器SQL模式” )。

如果使用 CHANGE MODIFY 缩短列上存在索引的列,并且结果列长度小于索引长度,MySQL会自动缩短索引。

对于由 CHANGE or RENAME COLUMN 重命名的 ,MySQL会自动将这些引用重命名为重命名的列:

  • 引用旧列的索引,包括不可见索引和禁用 MyISAM 索引。

  • 引用旧列的外键。

对于由 CHANGE or RENAME COLUMN 重命名的 ,MySQL不会自动将这些引用重命名为重命名的列:

  • 生成的列和分区表达式,用于引用重命名的列。 您必须使用 CHANGE 在与 ALTER TABLE 重命名列的语句 相同的 语句中 重新定义此类表达式

  • 引用重命名列的视图和存储程序。 您必须手动更改这些对象的定义以引用新列名称。

要重新排序表中的列,请使用 FIRST and AFTER in CHANGE MODIFY operations。

ALTER ... SET DEFAULT 或者 ALTER ... DROP DEFAULT 为列指定新的默认值或分别删除旧的默认值。 如果删除旧的默认值并且列可以是 NULL ,则新的默认值为 NULL 如果列不能 NULL ,则MySQL按 第11.7节“数据类型默认值”中 所述分配 默认值

主键和索引

DROP PRIMARY KEY 丢弃 主键 如果没有主键,则会发生错误。 有关主键性能特征的信息,尤其是 InnoDB 的性能特征 ,请参见 第8.3.2节“主键优化”

如果您 向表中 添加一个 UNIQUE INDEX PRIMARY KEY 多个表,MySQL会在任何非唯一索引之前存储它,以便尽早检测重复键。

DROP INDEX 删除索引。 这是标准SQL的MySQL扩展。 请参见 第13.1.27节“DROP INDEX语法” 要确定索引名称,请使用 SHOW INDEX FROM tbl_name

某些存储引擎允许您在创建索引时指定索引类型。 index_type 说明符 的语法 有关详细信息 ,请参见 第13.1.15节“CREATE INDEX语法” 首选位置在列列表之后。 在将来的MySQL版本中,将删除在列列表之前使用该选项的支持。 USING type_name USING

index_option values指定索引的其他选项。 USING 就是这样一个选择。 有关允许 index_option 值的 详细信息 ,请参见 第13.1.15节“CREATE INDEX语法”

RENAME INDEX old_index_name TO new_index_name 重命名索引。 这是标准SQL的MySQL扩展。 表的内容保持不变。 old_index_name 必须是表中未被同一 ALTER TABLE 语句 删除的现有索引的名称 new_index_name 是新索引名称,在应用更改后,不能复制结果表中索引的名称。 索引名称都不能 PRIMARY

如果 ALTER TABLE MyISAM 上使用 ,则所有非唯一索引都在单独的批处理中创建(至于 REPAIR TABLE )。 ALTER TABLE 当你有很多索引时, 这应该会 快得多。

对于 MyISAM 表,可以显式控制密钥更新。 使用 ALTER TABLE ... DISABLE KEYS 要告诉MySQL停止更新非唯一索引。 然后使用 ALTER TABLE ... ENABLE KEYS 重新创建缺失的索引。 MyISAM 使用比逐个插入密钥快得多的特殊算法来做到这一点,因此在执行批量插入操作之前禁用密钥应该会带来相当大的加速。 除了前面提到 ALTER TABLE ... DISABLE KEYS INDEX 权限之外, 使用还 需要 特权。

虽然非唯一索引被禁用,它们将被忽略语句,如 SELECT EXPLAIN ,否则会使用它们。

ALTER TABLE 声明之后,可能需要运行 ANALYZE TABLE 以更新索引基数信息。 请参见 第13.7.6.22节“SHOW INDEX语法”

ALTER INDEX 操作允许索引可见或不可见。 优化程序不使用不可见索引。 索引可见性的修改适用于主键以外的索引(显式或隐式)。 此功能是存储引擎中性(支持任何引擎)。 有关更多信息,请参见 第8.3.12节“不可见索引”

外键和其他限制

FOREIGN KEY REFERENCES 条款由支持 InnoDB NDB 存储引擎,它实现 请参见 第15.6.1.5节“InnoDB和FOREIGN KEY约束” 对于其他存储引擎,将解析子句但忽略这些子句。 ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (...) REFERENCES ... (...)

对于 ALTER TABLE 不像 CREATE TABLE ADD FOREIGN KEY 忽略了 index_name 如果给,并使用自动生成的外键的名称。 作为解决方法,请包含 CONSTRAINT 指定外键名称 子句:

添加约束外name键(......)......
重要

MySQL默默地忽略内联 REFERENCES 规范,其中引用被定义为列规范的一部分。 MySQL仅接受 REFERENCES 作为单独 FOREIGN KEY 规范的 一部分定义的子句

注意

分区 InnoDB 表不支持外键。 此限制不适用于 NDB 表,包括那些明确分区的表 [LINEAR] KEY 有关更多信息,请参见 第23.6.2节“分区与存储引擎相关的限制”

MySQL Server和NDB Cluster都支持使用 ALTER TABLE 删除外键:

ALTER TABLE tbl_nameDROP FOREIGN KEY fk_symbol;

ALTER TABLE 支持 在同一 语句中 添加和删​​除外键 ALTER TABLE ... ALGORITHM=INPLACE 但不支持 ALTER TABLE ... ALGORITHM=COPY

服务器禁止更改可能导致参照完整性丢失的外键列。 解决方法是 ALTER TABLE ... DROP FOREIGN KEY 在更改列定义之前和 ALTER TABLE ... ADD FOREIGN KEY 之后使用。 禁止更改的示例包括:

  • 对可能不安全的外键列的数据类型的更改。 例如, 允许 更改 VARCHAR(20) VARCHAR(30) ,但将其更改 VARCHAR(1024) 为不是因为这会更改存储单个值所需的长度字节数。

  • 禁止将 NULL 更改 NOT NULL 为非严格模式,以防止将 NULL 转换 为默认的非 NULL 值,在引用的表中没有相应的值。 在严格模式下允许该操作,但如果需要任何此类转换,则会返回错误。

ALTER TABLE tbl_name RENAME new_tbl_name 更改内部生成的外键约束名称和以字符串 tbl_name _ibfk_ 开头 以反映新表名称的 用户定义的外键约束名称 InnoDB 将以字符串 tbl_name _ibfk_ 开头的外键约束名称解释 为内部生成的名称。

在MySQL 8.0.16之前, ALTER TABLE 仅允许以下限制版本的 CHECK 约束添加语法,该语法被解析并被忽略:

添加检查(expr

从MySQL 8.0.16开始, ALTER TABLE 允许 CHECK 添加,删除或更改现有表的约束:

  • 添加新约束:

    ALTER TABLE tbl_name
        ADD CONSTRAINT [ symbol] CHECK(expr)[[NOT] ENFORCED];
    

    约束语法元素的含义与for相同 CREATE TABLE 请参见 第13.1.20.7节“检查约束”

  • 删除名为的现有约束 symbol

    ALTER TABLE tbl_name
        DROP CHECK symbol;
    
  • 更改是否 symbol 强制执行 现有约束

    ALTER TABLE tbl_name
        ALTER CHECK symbol[NOT] ENFORCED;
    

DROP CHECK ALTER CHECK 条款是MySQL的扩展标准SQL。

如果表更改导致违反强制 CHECK 约束,则会发生错误并且不会修改表。 发生错误的操作示例:

  • 尝试将该 AUTO_INCREMENT 属性 添加 CHECK 约束中 使用的列

  • 尝试添加强制 CHECK 约束或强制执行 非强制 约束 CHECK ,现有行违反约束条件。

  • 尝试修改,重命名或删除 CHECK 约束中 使用的列 ,除非该约束也在同一语句中删除。 例外:如果 CHECK 约束仅引用单个列,则删除列会自动删除约束。

ALTER TABLE tbl_name RENAME new_tbl_name 更改内部生成的和用户定义的 CHECK 约束名称,以字符串 tbl_name _chk_ 开头 以反映新的表名。 MySQL CHECK 将以字符串 tbl_name _chk_ 开头的约束名称 解释 为内部生成的名称。

更改字符集

要更改默认的表字符集和所有字符列( CHAR VARCHAR TEXT )到一个新的字符集,使用这样的语句:

ALTER TABLE tbl_nameCONVERT TO CHARACTER SET charset_name;

该语句还会更改所有字符列的排序规则。 如果指定no COLLATE 子句指示要使用的排序规则,则该语句将对字符集使用默认排序规则。 如果此排序规则不适合预期的表使用(例如,如果它将从区分大小写的排序规则更改为不区分大小写的排序规则),请明确指定排序规则。

对于具有的数据类型的列 VARCHAR 或一个 TEXT 种类, CONVERT TO CHARACTER SET 改变了数据类型必须确保新列足够长,以尽可能多的字符存储为原始列。 例如,一 TEXT 列有两个长度字节,用于存储列中值的字节长度,最大值为65,535。 对于 latin1 TEXT 列,每个字符都需要一个字节,因此该列最多可以存储65,535个字符。 如果将列转换为 utf8 ,则每个字符最多可能需要三个字节,最大可能长度为3×65,535 = 196,605字节。 该长度不适合 TEXT 列的长度字节,因此MySQL将数据类型转换为 MEDIUMTEXT ,这是长度字节可以记录值196,605的最小字符串类型。 同样, VARCHAR 列可能会转换为 MEDIUMTEXT

要避免更改刚才描述的类型的数据类型,请不要使用 CONVERT TO CHARACTER SET 相反,用于 MODIFY 更改单个列。 例如:

ALTER TABLE t MODIFY latin1_text_col文本字符集utf8;
ALTER TABLE t MODIFY latin1_varchar_col VARCHAR(M)CHARACTER SET utf8;

如果您指定 CONVERT TO CHARACTER SET binary CHAR VARCHAR TEXT 列转换为它们相应的二进制字符串类型( BINARY VARBINARY BLOB )。 这意味着列不再具有字符集,后续 CONVERT TO 操作将不适用于它们。

如果 charset_name DEFAULT 在一个 CONVERT TO CHARACTER SET 操作中,由命名的字符集 character_set_database 被用于系统变量。

警告

CONVERT TO 操作转换原始字符集和命名字符集之间的列值。 如果你在一个字符集中有一个列(如 ), 那么 不是 你想要的, latin1 但存储的值实际上使用了一些其他不兼容的字符集(如 utf8 )。 在这种情况下,您必须为每个此类列执行以下操作:

ALTER TABLE t1 CHANGE c1 c1 BLOB;
ALTER TABLE t1 CHANGE c1 c1 TEXT CHARACTER SET utf8;

这样做的原因是当您转换为 BLOB 或从 转换时没有转换

要仅更改 默认 字符集,请使用以下语句:

ALTER TABLE tbl_nameDEFAULT CHARACTER SET charset_name;

这个词 DEFAULT 是可选的。 如果未指定稍后添加到表中的列的字符集(例如,with ALTER TABLE ... ADD column ,则默认字符集是使用的字符集

foreign_key_checks 系统变量启用,这是默认设置,字符集转换是不允许的,其中包括在一个外键约束使用的字符串列的表。 解决方法是 foreign_key_checks 在执行字符集转换之前 禁用 在重新启用之前,必须对外键约束中涉及的两个表执行转换 foreign_key_checks 如果 foreign_key_checks 在仅转换其中一个表后 重新启用 ,则 由于在这些操作期间发生的隐式转换, ON DELETE CASCADE ON UPDATE CASCADE 操作可能会破坏引用表中的数据(Bug#45290,Bug#74816)。

丢弃和导入InnoDB表空间

一个 InnoDB 在自己创建的表 文件的每个表的 表空间可以被丢弃,并使用进口 DISCARD TABLESPACE IMPORT TABLESPACE 选项。 这些选项可用于从备份导入每个表的文件表空间,或者将每个表的文件表空间从一个数据库服务器复制到另一个数据库服务器。 请参见 第15.6.3.7节“将表空间复制到另一个实例”

MyISAM表的行顺序

ORDER BY 使您能够以特定顺序创建包含行的新表。 当您知道在大多数时间以特定顺序查询行时,此选项很有用。 通过在对表进行重大更改后使用此选项,您可以获得更高的性能。 在某些情况下,如果表格由您想要稍后订购的列按顺序排列,则可能会使MySQL更容易排序。

注意

插入和删除后,表不会保持指定的顺序。

ORDER BY 语法允许为排序指定一个或多个列名,每个列名可选地可以分别跟随 ASC DESC 指示升序或降序排序。 默认为升序。 只允许列名作为排序标准; 不允许使用任意表达式。 该条款应在任何其他条款之后最后给出。

ORDER BY InnoDB 没有意义, 因为 InnoDB 总是根据 聚簇索引 对表行进行排序

在分区表上使用时, ALTER TABLE ... ORDER BY 仅对每个分区中的行进行排序。

分区选项

partition_options 表示可以与分区表一起使用的选项,用于重新分区,添加,删除,丢弃,导入,合并和拆分分区,以及执行分区维护。

这是可能的 ALTER TABLE 语句包含一个 PARTITION BY REMOVE PARTITIONING 子句中,除其他更改规格,但 PARTITION BY 还是 REMOVE PARTITIONING 子句必须最后任何其他规格后指定。 ADD PARTITION DROP PARTITION DISCARD PARTITION IMPORT PARTITION COALESCE PARTITION REORGANIZE PARTITION EXCHANGE PARTITION ANALYZE PARTITION CHECK PARTITION ,和 REPAIR PARTITION 选项不能与其他单一更改规格组合 ALTER TABLE ,因为选择刚上市就单个分区的行为。

有关分区选项的更多信息,请参见 第13.1.20节“CREATE TABLE语法” 第13.1.9.1节“ALTER TABLE分区操作” 有关 ALTER TABLE ... EXCHANGE PARTITION 语句的 信息和示例 ,请参见 第23.3.3节“使用表交换分区和子分区”

13.1.9.1 ALTER TABLE分区操作

与分区相关的子句 ALTER TABLE 可以与分区表一起用于重新分区,添加,删除,丢弃,导入,合并和拆分分区,以及执行分区维护。

  • 只需 在分区表上 使用 partition_options 子句, ALTER TABLE 就可以根据定义的分区方案对表进行重新分区 partition_options 此子句始终 PARTITION BY 以及适用于该 partition_options 子句 的相同语法和其他规则 开始 CREATE TABLE (有关更多详细信息,请参见 第13.1.20节“CREATE TABLE语法” ),并且还可用于对现有表进行分区。尚未分区。 例如,考虑如下所示定义的(非分区)表:

    CREATE TABLE t1(
        id INT,
        year_col INT
    );
    

    通过此语句 HASH ,可以使用 id 列作为分区键 将此表分区 为8个分区:

    改编表t1
        哈希分区(id)
        PARTITIONS 8;
    

    MySQL支持一个 ALGORITHM 选项 [SUB]PARTITION BY [LINEAR] KEY ALGORITHM=1 在计算分区中行的位置时,服务器使用与MySQL 5.1相同的密钥散列函数; ALGORITHM=2 表示服务器使用默认为 KEY MySQL 5.5及更高版本中的 分区表 实现和使用的密钥散列函数 (使用MySQL 5.5及更高版本中使用的密钥散列函数创建的分区表不能由MySQL 5.1服务器使用。)不指定该选项与使用具有相同的效果 ALGORITHM=2 此选项主要用于升级或降级时 [LINEAR] KEY MySQL 5.1和更高版本MySQL版本之间的分区表,或者用于创建 可在MySQL 5.1服务器上使用的MySQL 5.5或更高版本服务器上 KEY LINEAR KEY 之上 分区的表

    使用 ALTER TABLE ... PARTITION BY 语句 产生的 表必须遵循与 使用 语句创建的规则相同的规则 CREATE TABLE ... PARTITION BY 这包括管理表可能具有的任何唯一键(包括任何主键)与分区表达式中使用的列之间的关系的规则,如 第23.6.1节“分区键,主键和独特的钥匙“ CREATE TABLE ... PARTITION BY 指定分区数 规则也适用于 ALTER TABLE ... PARTITION BY

    partition_definition 子句 ALTER TABLE ADD PARTITION 支持与语句的同名子句相同的选项 CREATE TABLE (有关 语法和说明, 请参见 第13.1.20节“CREATE TABLE语法” 。)假设您创建了分区表,如下所示:

    CREATE TABLE t1(
        id INT,
        year_col INT
    按范围划分(year_col)(
        分数p0值低于(1991),
        分区p1值低于(1995),
        分区p2值低于(1999)
    );
    

    您可以 p3 向此表 添加新分区 ,以存储小于以下值的值 2002

    更改表t1添加分区(分区p3值小于(2002));
    

    DROP PARTITION 可用于删除一个或多个 RANGE LIST 分区。 这种说法不能使用 HASH KEY 分区; 相反,使用 COALESCE PARTITION (见本节后面部分)。 存储在 partition_names 列表中 指定的已删除分区中的任何数据都将被 丢弃。 例如,根据 t1 先前定义 的表 ,您可以删除命名的分区 p0 p1 如下所示:

    ALTER TABLE t1 DROP PARTITION p0,p1;
    
    注意

    DROP PARTITION 不适用于使用 NDB 存储引擎的 请参见 第23.3.1节“RANGE和LIST分区的管理” 第22.1.7节“NDB集群的已知限制”

    ADD PARTITION 并且 DROP PARTITION 目前不支持 IF [NOT] EXISTS

    DISCARD PARTITION ... TABLESPACE IMPORT PARTITION ... TABLESPACE 选项延长 传输表空间 功能个别 InnoDB 表分区。 每个 InnoDB 表分区都有自己的表空间文件( .ibd 文件)。 传输表空间 功能可以轻松地将表空间从正在运行的MySQL服务器实例复制到另一个正在运行的实例,或者在同一实例上执行还原。 这两个选项都使用逗号分隔的一个或多个分区名称列表。 例如:

    更改表t1 DISCARD PARTITION p2,p3 TABLESPACE;
    
    更改表t1导入分区p2,p3 TABLESPACE;
    

    在子分区表上 运行时 DISCARD PARTITION ... TABLESPACE IMPORT PARTITION ... TABLESPACE 允许分区和子分区名称。 指定分区名称时,将包括该分区的子分区。

    传输表空间 功能还支持复制或还原分区 InnoDB 表(所有分区一次)。 有关其他信息,请参见 第15.6.3.7节“将表空间复制到另一个实例” ,以及 第15.6.3.7.1节“可传输表空间示例”

    支持分区表的重命名。 您可以使用间接重命名单个分区 ALTER TABLE ... REORGANIZE PARTITION ; 但是,此操作会复制分区的数据。

    要从选定分区中删除行,请使用该 TRUNCATE PARTITION 选项。 此选项采用一个或多个逗号分隔的分区名称列表。 考虑一下 t1 这个语句创建的表:

    CREATE TABLE t1(
        id INT,
        year_col INT
    按范围划分(year_col)(
        分数p0值低于(1991),
        分区p1值低于(1995),
        分区p2值低于(1999),
        分区p3的价值低于(2003年),
        分区p4价值低于(2007年)
    );
    

    要从分区中删除所有行 p0 ,请使用以下语句:

    ALTER TABLE t1 TRUNCATE PARTITION p0;
    

    刚才显示的语句与以下 DELETE 语句 具有相同的效果

    DELETE FROM t1 WHERE year_col <1991;
    

    截断多个分区时,分区不必是连续的:这可以大大简化分区表上的删除操作,否则 WHERE 如果使用 DELETE 语句 ,则需要非常复杂的 条件 例如,此语句删除分区中的所有行, p1 并且 p3

    ALTER TABLE t1 TRUNCATE PARTITION p1,p3;
    

    DELETE 这里显示了 一个等效 语句:

    从t1 WHERE中删除
        (year_col> = 1991 AND year_col <1995)
        要么
        (year_col> = 2003 AND year_col <2007);
    

    如果使用 ALL 关键字代替分区名称列表,则该语句将作用于所有表分区。

    TRUNCATE PARTITION 只是删除行; 它不会改变表本身或其任何分区的定义。

    要验证行是否已删除,请 INFORMATION_SCHEMA.PARTITIONS 使用以下查询 检查 表:

    SELECT PARTITION_NAME,TABLE_ROWS
        来自INFORMATION_SCHEMA.PARTITIONS
        WHERE TABLE_NAME ='t1';
    

    COALESCE PARTITION 可以与分区的表一起使用, HASH 或者 KEY 减少分区数 number 假设您已创建表 t2 ,如下所示:

    创建表t2(
        名称VARCHAR(30),
        开始日期
    哈希分区(年(开始))
    分数6;
    

    要将使用的分区数 t2 从6减少到4,请使用以下语句:

    更改表t2 COALESCE PARTITION 2;
    

    最后一个 number 分区中 包含的数据 将合并到其余分区中。 在这种情况下,分区4和5将合并到前4个分区(编号为0,1,2和3的分区)中。

    要更改分区表使用的部分但不是全部分区,可以使用 REORGANIZE PARTITION 可以通过以下几种方式使用此语句:

    • 将一组分区合并到一个分区中。 这是通过在 partition_names 列表中 命名多个分区 并为其提供单个定义来完成的 partition_definition

    • 将现有分区拆分为多个分区。 通过为单个分区命名 partition_names 并提供多个 分区来完成此任务 partition_definitions

    • 更改使用定义的分区子集的范围 VALUES LESS THAN 使用定义的分区子集 的值列表 VALUES IN

    注意

    对于没有明确命名的分区,MySQL的自动提供的默认名称 p0 p1 p2 ,等等。 对于子分区也是如此。

    有关 ALTER TABLE ... REORGANIZE PARTITION 语句的 更多详细信息和示例 ,请参见 第23.3.1节“RANGE和LIST分区的管理”

  • 要使用表交换表分区或子分区,请使用该 ALTER TABLE ... EXCHANGE PARTITION 语句,即将分区或子分区中的任何现有行移动到非分区表,将非分区表中的任何现有行移动到表分区或子分区。

    有关用法信息和示例,请参见 第23.3.3节“使用表交换分区和子分区”

  • 有几个选项提供分区维护和修复功能,类似于通过诸如 CHECK TABLE REPAIR TABLE (以及分区表也支持的 语句 为非 分区表实现的功能;有关更多信息,请参见 第13.7.3节“表维护语句” )。 这些措施包括 ANALYZE PARTITION CHECK PARTITION OPTIMIZE PARTITION REBUILD PARTITION ,和 REPAIR PARTITION 这些选项中的每一个都采用 partition_names 由一个或多个分区名称组成的子句,以逗号分隔。 分区必须已存在于目标表中。 您也可以使用 ALL 关键字代替 partition_names 在这种情况下,该语句作用于所有表分区。 有关更多信息和示例,请参见 第23.3.4节“分区维护”

    InnoDB 目前不支持按分区优化; ALTER TABLE ... OPTIMIZE PARTITION 导致整个表重建和分析,并发出适当的警告。 (Bug#11751825,Bug#42822)要解决此问题,请使用 ALTER TABLE ... REBUILD PARTITION ALTER TABLE ... ANALYZE PARTITION 不是。

    ANALYZE PARTITION CHECK PARTITION OPTIMIZE PARTITION ,和 REPAIR PARTITION 选项不支持未分区表。

  • REMOVE PARTITIONING 使您可以删除表的分区,而不会影响表或其数据。 此选项可以与其他 ALTER TABLE 选项 结合使用, 例如用于添加,删除或重命名列或索引的选项。

  • 使用该 ENGINE 选项 ALTER TABLE 可更改表使用的存储引擎,而不会影响分区。 目标存储引擎必须提供自己的分区处理程序。 只有 InnoDB NDB 存储引擎有本机分区处理程序; NDB MySQL 8.0目前不支持。

这是可能的 ALTER TABLE 语句包含一个 PARTITION BY REMOVE PARTITIONING 子句中,除其他更改规格,但 PARTITION BY 还是 REMOVE PARTITIONING 子句必须最后任何其他规格后指定。

ADD PARTITION DROP PARTITION COALESCE PARTITION REORGANIZE PARTITION ANALYZE PARTITION CHECK PARTITION ,和 REPAIR PARTITION 选项不能与其他单一更改规格组合 ALTER TABLE ,因为选择刚上市就单个分区的行为。 有关更多信息,请参见 第13.1.9.1节“ALTER TABLE分区操作”

只有以下任一选项的单个实例可以在给定的使用 ALTER TABLE 声明: PARTITION BY ADD PARTITION DROP PARTITION TRUNCATE PARTITION EXCHANGE PARTITION REORGANIZE PARTITION ,或 COALESCE PARTITION ANALYZE PARTITION CHECK PARTITION OPTIMIZE PARTITION REBUILD PARTITION REMOVE PARTITIONING

例如,以下两个语句无效:

ALTER TABLE t1 ANALYZE PARTITION p1,ANALYZE PARTITION p2;

ALTER TABLE t1 ANALYZE PARTITION p1,CHECK PARTITION p2;

在第一种情况下,您可以 使用单个语句同时 分析分区 p1 p2 表, t1 并使用单个 ANALYZE PARTITION 选项列出要分析的两个分区,如下所示:

ALTER TABLE t1 ANALYZE PARTITION p1,p2;

在第二种情况下,不可能 同时在同一个表的不同分区上 执行 ANALYZE CHECK 操作。 相反,您必须发出两个单独的语句,如下所示:

ALTER TABLE t1 ANALYZE PARTITION p1;
ALTER TABLE t1检查分区p2;

REBUILD 子分区目前不支持操作。 所述 REBUILD 关键字被明确地与子分区不允许,并且使得 ALTER TABLE 如果这样用失败,错误。

CHECK PARTITION REPAIR PARTITION 当要检查或修复的分区包含任何重复的键错误时 操作失败。

有关这些语句的更多信息,请参见 第23.3.4节“分区维护”

13.1.9.2 ALTER TABLE和生成的列

ALTER TABLE 允许生成的列操作是 ADD MODIFY ,和 CHANGE

  • 可以添加生成的列。

    CREATE TABLE t1(c1 INT);
    更改表t1添加列c2 INT始终作为(c1 + 1)存储;            
    
  • 可以修改生成列的数据类型和表达式。

    创建表t1(c1 INT,c2 INT始终作为(c1 + 1)存储);
    更改表t1修改栏c2 TINYINT始终作为(c1 + 5)存储;
    
  • 如果没有其他列引用它们,则可以重命名或删除生成的列。

    创建表t1(c1 INT,c2 INT始终作为(c1 + 1)存储);
    更改表t1更改c2 c3 INT始终作为(c1 + 1)存储;
    ALTER TABLE t1 DROP COLUMN c3;            
    
  • 虚拟生成的列不能更改为存储的生成列,反之亦然。 要解决此问题,请删除该列,然后使用新定义添加该列。

    创建表t1(c1 INT,c2 INT始终为(c1 + 1)VIRTUAL);
    ALTER TABLE t1 DROP COLUMN c2;
    更改表t1添加列c2 INT始终作为(c1 + 1)存储;           
    
  • 非生成列可以更改为已存储但不是虚拟生成列。

    CREATE TABLE t1(c1 INT,c2 INT);
    更改表t1修改栏c2 INT始终作为(c1 + 1)存储;            
    
  • 存储但不是虚拟生成的列可以更改为非生成列。 存储的生成值将成为非生成列的值。

    创建表t1(c1 INT,c2 INT始终作为(c1 + 1)存储);
    ALTER TABLE t1 MODIFY COLUMN c2 INT;            
    
  • ADD COLUMN 不是存储列的就地操作(不使用临时表),因为表达式必须由服务器评估。 对于存储的列,索引更改将在适当的位置完成,并且表达式更改不会就位。 列注释的更改已就位。

  • 对于非分区表, ADD COLUMN 以及 DROP COLUMN 虚拟列的就地操作。 但是,无法在与其他 ALTER TABLE 操作 组合的情况下执行添加或删除虚拟列

    对于分区表, ADD COLUMN 并且 DROP COLUMN 不是虚拟列的就地操作。

  • InnoDB 支持虚拟生成列上的二级索引。 在虚拟生成列上添加或删除辅助索引是就地操作。 有关更多信息,请参见 第13.1.20.10节“二级索引和生成的列”

  • VIRTUAL 生成的列添加到表中或进行修改时,无法确保生成的列表达式计算的数据不会超出列的范围。 这可能导致返回不一致的数据和意外失败的语句。 允许控制是否对此类列, ALTER TABLE 支持 WITHOUT VALIDATION WITH VALIDATION 子句 进行验证

    • 使用 WITHOUT VALIDATION (默认情况下,如果未指定none子句),将执行就地操作(如果可能),不检查数据完整性,并且语句更快完成。 但是,如果值超出范围,稍后从表中读取可能会报告列的警告或错误。

    • WITH VALIDATION ALTER TABLE 复制表。 如果发生超出范围或任何其他错误,则语句失败。 由于执行了表副本,因此语句需要更长时间。

    WITHOUT VALIDATION 并且 WITH VALIDATION 只有被允许 ADD COLUMN CHANGE COLUMN MODIFY COLUMN 操作。 否则, ER_WRONG_USAGE 会发生错误。

  • 如果表达式求值导致截断或向函数提供不正确的输入,则 ALTER TABLE 语句将终止并显示错误,并拒绝DDL操作。

  • ALTER TABLE 更改列的默认值 语句 col_name 还可能更改引用列使用 col_name 的生成列表达式的值,这可能会更改引用该列的生成列表达式的值 因此, 如果任何生成的列表达式使用,则更改列定义的操作会导致表重建 DEFAULT(col_name) ALTER TABLE DEFAULT()

13.1.9.3 ALTER TABLE示例

t1 如下所示创建 的表开始

CREATE TABLE t1(INTEGER,b CHAR(10));

要将表重命名 t1 t2

ALTER TABLE t1 RENAME t2;

若要更改列 a INTEGER TINYINT NOT NULL (名字一样),并更改列 b CHAR(10) CHAR(20) 以及来自重命名 b c

ALTER TABLE t2修改TINYINT NOT NULL,更改bc CHAR(20);

要添加 TIMESTAMP 名为 的新 d

ALTER TABLE t2 ADD d TIMESTAMP;

要添加对列的索引 d UNIQUE 对列索引 a

ALTER TABLE t2 ADD INDEX(d),ADD UNIQUE(a);

要删除列 c

ALTER TABLE t2 DROP COLUMN c;

要添加 AUTO_INCREMENT 名为 的新 整数列 c

ALTER TABLE t2 ADD c INT UNSIGNED NOT NULL AUTO_INCREMENT,
  添加主要密钥(c);

我们索引 c (作为a PRIMARY KEY )因为 AUTO_INCREMENT 列必须被索引,并且我们声明 c NOT NULL 因为主键列不能 NULL

对于 NDB 表,还可以更改用于表或列的存储类型。 例如,考虑 NDB 如下所示创建 表:

MySQL的> CREATE TABLE t1 (c1 INT) TABLESPACE ts_1 ENGINE NDB;
查询OK,0行受影响(1.27秒)

要将此表转换为基于磁盘的存储,可以使用以下 ALTER TABLE 语句:

MySQL的> ALTER TABLE t1 TABLESPACE ts_1 STORAGE DISK;
查询正常,0行受影响(2.99秒)
记录:0重复:0警告:0

MySQL的> SHOW CREATE TABLE t1\G
*************************** 1。排******************** *******
       表:t1
创建表:CREATE TABLE`t1`(
  `c1` int(11)DEFAULT NULL
)/ *!50100 TABLESPACE ts_1存储盘* /
ENGINE = ndbcluster DEFAULT CHARSET = latin1
1排(0.01秒)

最初创建表时,没有必要引用表空间; 但是,表空间必须由以下引用 ALTER TABLE

MySQL的> CREATE TABLE t2 (c1 INT) ts_1 ENGINE NDB;
查询正常,0行受影响(1.00秒)

mysql> ERROR 1005(HY000):无法创建表'c。#sql-1750_3'(错误号:140) 
mysql>ALTER TABLE t2 STORAGE DISK;
ALTER TABLE t2 TABLESPACE ts_1 STORAGE DISK;
查询OK,0行受影响(3.42秒)
记录:0重复:0警告:0
MySQL的> SHOW CREATE TABLE t2\G
*************************** 1。排******************** *******
       表:t1
创建表:CREATE TABLE`t2`(
  `c1` int(11)DEFAULT NULL
)/ *!50100 TABLESPACE ts_1存储盘* /
ENGINE = ndbcluster DEFAULT CHARSET = latin1
1排(0.01秒)

要更改单个列的存储类型,您可以使用 ALTER TABLE ... MODIFY [COLUMN] 例如,假设您使用以下 CREATE TABLE 语句 创建具有两列的NDB Cluster Disk Data表

mysql> CREATE TABLE t3 (c1 INT, c2 INT)
    - >     TABLESPACE ts_1 STORAGE DISK ENGINE NDB;
查询OK,0行受影响(1.34秒)

要将列 c2 从基于磁盘的存储 更改 为内存存储,请在ALTER TABLE语句使用的列定义中包含STORAGE MEMORY子句,如下所示:

MySQL的> ALTER TABLE t3 MODIFY c2 INT STORAGE MEMORY;
查询正常,0行受影响(3.14秒)
记录:0重复:0警告:0

您可以通过 STORAGE DISK 类似的方式 使用内存中的列到基于磁盘的列

c1 使用基于磁盘的存储,因为这是表的缺省值(由 STORAGE DISK 语句中的 表级 子句 确定 CREATE TABLE )。 但是,列 c2 使用内存存储,这可以在SHOW的输出中看到 CREATE TABLE

MySQL的> SHOW CREATE TABLE t3\G
*************************** 1。排******************** *******
       表:t3
创建表:CREATE TABLE`t3`(
  `c1` int(11)DEFAULT NULL,
  `c2` int(11)/ *!50120 STORAGE MEMORY * / DEFAULT NULL
)/ *!50100 TABLESPACE ts_1存储磁盘* / ENGINE = ndbcluster DEFAULT CHARSET = latin1
1排(0.02秒)

添加 AUTO_INCREMENT 列时,列值将自动填入序列号。 对于 MyISAM 表,您可以通过执行 之前 或使用 表选项 来设置第一个序列号 SET INSERT_ID=value ALTER TABLE AUTO_INCREMENT=value

对于 MyISAM 表,如果不更改 AUTO_INCREMENT 列,则序列号不受影响。 如果删除 AUTO_INCREMENT 列然后添加另一 AUTO_INCREMENT 列,则从1开始重新排序数字。

使用复制时,向 AUTO_INCREMENT 表中 添加 列可能不会在从属和主服务器上生成相同的行顺序。 发生这种情况是因为行的编号顺序取决于用于表的特定存储引擎以及插入行的顺序。 如果在主站和从站上具有相同的顺序很重要,则必须在分配 AUTO_INCREMENT 号码 之前对行进行排序 假设您要向 AUTO_INCREMENT 表中 添加一 t1 ,以下语句将生成一个 t2 相同 t1 但具有 AUTO_INCREMENT 的新表

CREATE TABLE t2(id INT AUTO_INCREMENT PRIMARY KEY)
SELECT * FROM t1 ORDER BY col1,col2;

这假设表 t1 有列 col1 col2

这组语句还将生成一个 与添加 t2 相同 的新表 t1 AUTO_INCREMENT

CREATE TABLE t2 LIKE t1;
ALTER TABLE t2 ADD id INT AUTO_INCREMENT PRIMARY KEY;
INSERT INTO t2 SELECT * FROM t1 ORDER BY col1,col2;
重要

为了保证主服务器和从服务器上的相同顺序 必须在 子句中 引用 所有 t1 ORDER BY

无论用于创建和填充具有 AUTO_INCREMENT 的副本的方法如何 ,最后一步是删除原始表,然后重命名副本:

DROP TABLE t1;
ALTER TABLE t2 RENAME t1;

13.1.10 ALTER TABLESPACE语法

仅ALTER [UNDO] TABLESPACE NDB:   
    {ADD | DROP} DATAFILE' 'tablespace_name
  file_name
    [INITIAL_SIZE [=]尺寸]
    [等待]
  InnoDB和NDB: 
    [仅限 RENAME TOtablespace_name] 
   InnoDB:
    [SET {ACTIVE | INACTIVE}]
    [ENCRYPTION [=] {'Y'| 'N'}]
  InnoDB和NDB: 
    [ENGINE [=]engine_name]

此语句与 NDB InnoDB 表空间一起使用。 它可用于向 NDB 表空间 添加新数据文件或从 表空间 删除数据文件 它还可用于重命名NDB Cluster Disk Data表空间,重命名 InnoDB 常规表空间,加密 InnoDB 常规表空间或将 InnoDB undo表空间 标记 为活动或非活动。

UNDO MySQL 8.0.14中引入 关键字与该 SET {ACTIVE|INACTIVE} 子句一起 使用, 以将 InnoDB 撤消表空间 标记 为活动或非活动。 有关更多信息,请参见 第15.6.3.4节“撤消表空间”

ADD DATAFILE 变量使您可以 NDB 使用 INITIAL_SIZE 子句 指定 磁盘数据表空间 的初始大小 ,其中 size 以字节为单位进行测量; 默认值为134217728(128 MB)。 您可以选择 size 使用一个字母的缩写,一个数量级,类似于中使用的那些 my.cnf 通常,这是字母 M (兆字节)或 G (千兆字节)之一。

在32位系统上,支持的最大值为 INITIAL_SIZE 4294967296(4 GB)。 (Bug#29186)

INITIAL_SIZE 是明确的四舍五入的 CREATE TABLESPACE

创建数据文件后,其大小无法更改; 但是,您可以使用其他 ALTER TABLESPACE ... ADD DATAFILE 语句 将更多数据文件添加到NDB表空间

ALTER TABLESPACE ... ADD DATAFILE 与使用 ENGINE = NDB 中,每个群集的数据节点上创建的数据文件,但在仅生成一个行 INFORMATION_SCHEMA.FILES 表。 有关详细信息,请参阅此表的说明以及 第22.5.13.1节“NDB集群磁盘数据对象” 表空间 ADD DATAFILE 不支持 InnoDB

使用 DROP DATAFILE ALTER TABLESPACE 下降的数据文件“ file_name 从NDB表”。 您不能从任何表正在使用的表空间中删除数据文件; 换句话说,数据文件必须为空(不使用扩展数据块)。 请参见 第22.5.13.1节“NDB集群磁盘数据对象” 此外,要删除的任何数据文件必须先前已使用 CREATE TABLESPACE 添加到表空间 ALTER TABLESPACE 表空间 DROP DATAFILE 不支持 InnoDB

WAIT 被解析但被忽略。 它旨在用于未来的扩展。

ENGINE 子句指定了表空间使用的存储引擎,已弃用,将在以后的版本中删除。 表空间存储引擎是数据字典已知的,使该 ENGINE 子句过时。 如果指定了存储引擎,则它必须与数据字典中定义的表空间存储引擎匹配。 engine_name NDB 表空间 兼容 的唯一值 NDB NDBCLUSTER

RENAME TO autocommit 无论 autocommit 设置 如何, 都以 模式 隐式执行操作

RENAME TO 操作不能同时被执行 LOCK TABLES 或者 FLUSH TABLES WITH READ LOCK 是在驻留在表空间的表的效果。

在重命名表空间时,驻留在通用表空间中的表采用 独占 元数据锁 ,这可防止并发DDL。 支持并发DML。

CREATE TABLESPACE 需要 权限才能重命名 InnoDB 常规表空间。

ENCRYPTION 子句启用或禁用 InnoDB 常规表空间或 mysql 系统表空间的 页级数据加密 MySQL 8.0.13中引入了对通用表空间的加密支持。 mysql MySQL 8.0.16中引入 了对 系统表空间的 加密支持

必须先安装并配置密钥环插件,然后才能启用加密。

从MySQL 8.0.16开始,如果 table_encryption_privilege_check 启用了 变量, TABLE_ENCRYPTION_ADMIN 则需要 使用 权限来更改具有与 ENCRYPTION 设置不同 子句设置 的常规表空间 default_table_encryption

如果表空间中的任何表属于使用定义的模式,则对通用表空间启用加密会失败 DEFAULT ENCRYPTION='N' 同样,如果通用表空间中的任何表属于定义的模式,则禁用加密会失败 DEFAULT ENCRYPTION='Y' DEFAULT ENCRYPTION 模式选项在MySQL 8.0.16介绍。

如果 ALTER TABLESPACE 在通用表空间上执行 语句不包含 ENCRYPTION 子句,则表空间将保留其当前加密状态,而不管 default_table_encryption 设置 如何

对通用表空间或 mysql 系统表空间进行加密时,驻留在表空间中的所有表都将被加密。 同样,在加密表空间中创建的表也是加密的。

INPLACE 在更改 ENCRYPTION 通用表空间或 mysql 系统表空间 属性 时使用 算法 INPLACE 算法允许驻留在表空间中的表上的并发DML。 并发DDL被阻止。

有关更多信息,请参见 第15.6.3.9节“InnoDB静态数据加密”

13.1.11 ALTER VIEW语法

改变
    [ALGORITHM = {UNDEFINED | MERGE | 不是Temptable}]
    [DEFINER = user]
    [SQL SECURITY {DEFINER | INVOKER}]
    查看view_name[(column_list)]select_statement
    [WITH [CASCADED | 本地]检查选项]

此语句更改必须存在的视图的定义。 语法是类似于对 CREATE VIEW 第13.1.23,“CREATE VIEW语法” )。 此语句需要 视图的权限 CREATE VIEW DROP 特权,以及 SELECT 语句中 引用的每个列的某些特权 ALTER VIEW 仅允许定义者或用户提供 SET_USER_ID SUPER 特权。

13.1.12 CREATE DATABASE语法

创建{数据库| SCHEMA} [如果不存在] db_name
    [ create_specification] ......

create_specification
    [DEFAULT] CHARACTER SET [=] charset_name
  | [DEFAULT] COLLATE [=]collation_name
  | DEFAULT ENCRYPTION [=] {'Y'| 'N'}

CREATE DATABASE 创建具有给定名称的数据库。 要使用此语句,您需要 CREATE 数据库 权限。 CREATE SCHEMA 是...的同义词 CREATE DATABASE

如果数据库存在且您未指定,则会发生错误 IF NOT EXISTS

CREATE DATABASE 在具有活动 LOCK TABLES 语句 的会话中不允许

create_specification options指定数据库特征。 数据库特征存储在数据字典中。

MySQL中的数据库实现为包含与数据库中的表对应的文件的目录。 由于最初创建数据库时没有表,因此该 CREATE DATABASE 语句仅在MySQL数据目录下创建一个目录。 第9.2节“模式对象名称” 中给出了允许的数据库名称的规则 如果数据库名称包含特殊字符,则数据库目录的名称包含这些字符的编码版本,如 第9.2.3节“标识符到文件名的映射”中所述

在MySQL 8.0中不支持通过在 数据目录下手动创建目录(例如,使用 mkdir )来 创建数据库目录

您还可以使用 mysqladmin 程序创建数据库。 请参见 第4.5.2节“ mysqladmin - 管理MySQL服务器的客户端”

13.1.13 CREATE EVENT语法

创建
    [DEFINER = user]
    事件
    [IF NOT EXISTS]
    event_name
    按照时间表 schedule
    [完成[NOT] PRESERVE]
    [ENABLE | 禁用| 禁止在[SLAVE]
    [评论' string']event_body;

schedule
    AT timestamp[+ INTERVAL interval] ......
  | 每个interval
    [开始timestamp[+间隔interval] ...]
    [结束timestamp[+ INTERVAL interval] ...]

intervalquantity{年| QUARTER | 月| 一天| 小时| 分钟|
              周| 第二| YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
              DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}

此语句创建并计划新事件。 除非启用了事件计划程序,否则该事件将不会运行。 有关检查事件调度程序状态并在必要时启用它的信息,请参见 第24.4.2节“事件调度程序配置”

CREATE EVENT 需要对 EVENT 要在其中创建事件的模式 权限。 如果该 DEFINER 子句存在,则所需的权限取决于 user 值,如 第24.6节“存储对象访问控制”中所述

有效 CREATE EVENT 声明 的最低要求 如下:

  • 关键字 CREATE EVENT 加上事件名称,它唯一标识数据库模式中的事件。

  • 一个 ON SCHEDULE 子句,用于确定事件执行的时间和频率。

  • 一个 DO 子句,包含要由事件执行的SQL语句。

这是最小 CREATE EVENT 语句 的示例

创造事件myevent
    在CURRENT_TIMESTAMP + INTERVAL 1小时的时间表
      更新myschema.mytable SET mycol = mycol + 1;

前一个语句创建一个名为的事件 myevent 此事件在创建后执行一次 - 通过运行SQL语句,该语句将 myschema.mytable 表的 mycol 的值递增 1。

event_name 必须与64个字符的最大长度一个有效的MySQL标识符。 事件名称是不区分大小写,所以你不能有两个名为事件 myevent ,并 MyEvent 在同一个模式。 通常,管理事件名称的规则与存储例程的名称相同。 请参见 第9.2节“架构对象名称”

事件与架构相关联。 如果没有指示模式作为其一部分 event_name ,则假定默认(当前)模式。 要在特定模式中创建事件,请使用 语法 使用模式限定事件名称 schema_name.event_name

DEFINER 子句指定在事件执行时检查访问权限时要使用的MySQL帐户。 如果 DEFINER 子句,该 user 值应被指定为一个MySQL帐户 允许的 值取决于您拥有的权限,如 第24.6节“存储对象访问控制”中所述 有关事件安全性的其他信息,另请参阅该部分。 'user_name'@'host_name' CURRENT_USER CURRENT_USER() user

如果 DEFINER 省略 子句,则默认定义者是执行该 CREATE EVENT 语句 的用户 这与 DEFINER = CURRENT_USER 明确 指定相同

在事件正文中,该 CURRENT_USER 函数返回用于在事件执行时检查权限的帐户,即 DEFINER 用户。 有关事件中用户审计的信息,请参见 第6.2.22节“基于SQL的帐户活动审计”

IF NOT EXISTS 具有相同的含义为 CREATE EVENT CREATE TABLE :如果命名的事件 event_name 已经在相同的模式存在,不采取任何行动,而不会出现错误。 (但是,在这种情况下会产生警告。)

ON SCHEDULE 子句确定 event_body 事件 定义 时间,频率和持续时间 该子句采用以下两种形式之一:

  • AT timestamp 用于一次性事件。 它指定事件仅在给定的日期和时间执行一次,该日期和时间 timestamp 必须包括日期和时间,或者必须是解析为datetime值的表达式。 您可以 为此目的 使用 DATETIME TIMESTAMP 类型 的值 如果日期是过去的,则会发出警告,如下所示:

    MySQL的> SELECT NOW();
    + --------------------- +
    | 现在()|
    + --------------------- +
    | 2006-02-10 23:59:01 |
    + --------------------- +
    1排(0.04秒)
    
    mysql> CREATE EVENT e_totals
        - >      ON SCHEDULE AT '2006-02-10 23:59:00'
        - >     DO INSERT INTO test.totals VALUES (NOW());
    查询正常,0行受影响,1警告(0.00秒)
    
    MySQL的> SHOW WARNINGS\G
    *************************** 1。排******************** *******
      等级:注意
       代码:1588
    消息:事件执行时间是过去而完全没有
             PRESERVE已经确定。事件在此之后立即被删除
             创建。
    

    CREATE EVENT 无论出于何种原因本身无效的语句 - 失败并出现错误。

    您可以使用 CURRENT_TIMESTAMP 指定当前日期和时间。 在这种情况下,事件一旦创建就会起作用。

    要创建一个相对于当前日期和时间在某个时间点发生的事件 - 例如短语 从现在起三周 ”所表达的事件 - 您可以使用optional子句 部分由两部分组成,即数量和时间单位,并遵循 时间间隔中 描述的语法规则 ,但在定义事件时不能使用任何涉及微秒的单位关键字。 对于一些间隔类型,可以使用复杂的时间单位。 例如, 两分十秒 可以表示为 + INTERVAL interval interval + INTERVAL '2:10' MINUTE_SECOND

    您还可以组合间隔。 例如, AT CURRENT_TIMESTAMP + INTERVAL 3 WEEK + INTERVAL 2 DAY 相当于 从现在开始的三周和两天 这样一个条款的每一部分都必须以 + INTERVAL

  • 要定期重复操作,请使用 EVERY 子句。 EVERY 关键字后跟一个关键字 interval 的前一个讨论中所描述的 AT 关键字。 + INTERVAL 与所用 EVERY 。)例如, EVERY 6 WEEK 是指 每六周

    虽然 + INTERVAL 条款中不允许使用 EVERY 条款,但您​​可以使用相同的复杂时间单位 + INTERVAL

    一个 EVERY 子句可以包含一个可选的 STARTS 条款。 STARTS 后跟一个 timestamp 值, 值指示动作应该何时开始重复,并且还可以 用于指定 从现在起 的时间量 例如, 意思是 每三个月,从现在开始一周 同样,你可以表达 每两个星期,开始6小时15分钟从现在开始 未指定 与使用相同 + INTERVAL interval EVERY 3 MONTH STARTS CURRENT_TIMESTAMP + INTERVAL 1 WEEK EVERY 2 WEEK STARTS CURRENT_TIMESTAMP + INTERVAL '6:15' HOUR_MINUTE STARTS STARTS CURRENT_TIMESTAMP - 也就是说,为事件指定的操作在创建事件后立即开始重复。

    一个 EVERY 子句可以包含一个可选的 ENDS 条款。 ENDS 关键字后跟 timestamp 告诉MySQL时,该事件应停止重复值。 你也可以 ; 例如, 相当于 每十二小时,从现在开始三十分钟,从现在开始四周后 不使用 意味着事件继续无限期执行。 + INTERVAL interval ENDS EVERY 12 HOUR STARTS CURRENT_TIMESTAMP + INTERVAL 30 MINUTE ENDS CURRENT_TIMESTAMP + INTERVAL 4 WEEK ENDS

    ENDS 支持与复杂时间单位相同的语法 STARTS

    您可以 条款中 使用 STARTS ENDS 或两者都使用 EVERY

    如果重复事件未在其调度间隔内终止,则结果可能是同时执行事件的多个实例。 如果这是不合需要的,您应该建立一个机制来防止同时发生。 例如,您可以使用 GET_LOCK() 函数,或行或表锁定。

ON SCHEDULE 子句可以使用涉及内置MySQL函数和用户变量的表达式来获取 它包含的 任何 timestamp interval 值。 您不能在此类表达式中使用存储函数或用户定义函数,也不能使用任何表引用; 但是,你可以使用 SELECT FROM DUAL 对于这两个 CREATE EVENT ALTER EVENT 陈述 都是如此 在这种情况下,特别不允许引用存储函数,用户定义函数和表,并且失败并出现错误(参见Bug#22830)。

在时代 ON SCHEDULE 条款使用当前会话解释 time_zone 值。 这成为事件时区; 也就是说,用于事件调度的时区,它在执行时在事件中生效。 这些时间将转换为UTC并与 mysql.event 表中 的事件时区一起存储 这使得事件执行能够按照定义继续执行,而不管服务器时区或夏令时效果的任何后续更改。 有关事件时间表示的其他信息,请参见 第24.4.4节“事件元数据” 另请参见 第13.7.6.18节“显示事件语法” 第25.10节“INFORMATION_SCHEMA事件表”

通常,一旦事件过期,它会立即被删除。 您可以通过指定来覆盖此行为 ON COMPLETION PRESERVE 使用 ON COMPLETION NOT PRESERVE 仅仅使默认的非持久行为显式化。

您可以创建一个事件,但使用该 DISABLE 关键字 阻止它处于活动状态 或者,您可以使用 ENABLE 显式默认状态,该状态是活动的。 这最有用 ALTER EVENT (参见 第13.1.3节“ALTER EVENT语法” )。

第三个值也可能代替 ENABLE 出现 DISABLE ; DISABLE ON SLAVE 设置为复制从站上事件的状态,以指示事件是在主服务器上创建并复制到从服务器,但不在从服务器上执行。 请参见 第17.4.1.16节“调用调用的功能”

您可以使用 COMMENT 子句 为事件提供注释 comment 可以是您希望用于描述事件的任何最多64个字符的字符串。 注释文本是字符串文字,必须用引号括起来。

DO 子句指定事件携带的操作,并由SQL语句组成。 几乎任何可以在存储例程中使用的有效MySQL语句也可以用作已调度事件的操作语句。 (请参见 第C.1节“存储程序的限制” 。)例如,以下事件 每小时 e_hourly 删除 sessions 一次表中的 所有行 ,其中此表是 site_activity 模式的 一部分

e_hourly创造活动
    按照时间表
      每一个小时
    评论'每小时清理一次会议表。'
      从site_activity.sessions中删除;

MySQL存储在 sql_mode 创建或更改事件时生效 系统变量设置,并始终使用此设置执行事件, 而不管事件开始执行时当前服务器SQL模式如何

一个 CREATE EVENT 包含一个声明 ALTER EVENT 它在声明中 DO 条款似乎是成功的; 但是,当服务器尝试执行生成的预定事件时,执行将失败并显示错误。

注意

在事件中使用时, 诸如 SELECT SHOW 仅返回结果集的 语句 不起作用; 这些输出不会发送到MySQL监视器,也不会存储在任何地方。 但是,你可以使用语句,如 SELECT ... INTO INSERT INTO ... SELECT 该商店的结果。 (有关后者的实例,请参阅本节中的下一个示例。)

事件所属的模式是 DO 子句 中表引用的默认模式 必须使用正确的模式名称限定对其他模式中的表的任何引用。

与存储例程一样,您可以使用 关键字 DO 子句中 使用复合语句语法 ,如下所示: BEGIN END

分隔符|

创造事件e_daily
    按照时间表
      每一天
    评论'保存会话总数,然后每天清理表'
      开始
        INSERT INTO site_activity.totals(时间,总计)
          SELECT CURRENT_TIMESTAMP,COUNT(*)
            来自site_activity.sessions;
        从site_activity.sessions中删除;
      结束|

分隔符;

此示例使用该 delimiter 命令更改语句分隔符。 请参见 第24.1节“定义存储的程序”

在事件中,可以使用更复杂的复合语句,例如存储例程中使用的语句。 此示例使用局部变量,错误处理程序和流控制构造:

分隔符|

创造事件e
    按照时间表
      每隔5秒
      开始
        DECLARE v INTEGER;
        DECLARE CONTINUE HANDLER开始SQLEXCEPTION开始;

        SET v = 0;

        WHILE v <5 DO
          插入t1值(0);
          更新t2 SET s1 = s1 + 1;
          SET v = v + 1;
        结束时间;
    结束|

分隔符;

无法直接将参数传递给事件或从事件传递参数; 但是,可以使用事件中的参数调用存储的例程:

创建事件e_call_myproc
    按照时间表
      在CURRENT_TIMESTAMP + INTERVAL 1天
    请致电myproc(5,27);

如果事件的定义者具有足以设置全局系统变量的特权(请参见 第5.1.9.1节“系统变量特权” ),则事件可以读取和写入全局变量。 由于授予此类特权可能会导致滥用,因此必须特别注意这样做。

通常,在存储例程中有效的任何语句都可以用于事件执行的操作语句。 有关存储例程中允许的语句的更多信息,请参见 第24.2.1节“存储的例程语法” 您可以将事件创建为存储例程的一部分,但事件不能由另一个事件创建。

13.1.14 CREATE FUNCTION语法

CREATE FUNCTION 语句用于创建存储函数和用户定义函数(UDF):

13.1.15 CREATE INDEX语法

创建[UNIQUE | FULLTEXT | 空间]索引index_name
    [ index_type]
    ON tbl_namekey_part,...)
    [ index_option]
    [ algorithm_option| lock_option] ......

key_part:{ col_name[(length)] | expr)} [ASC | DESC]

index_option
    KEY_BLOCK_SIZE [=] value
  | index_type
  | 与PARSER parser_name
  | 评论' string'
  | {VISIBLE | 无形}

index_type
    使用{BTREE | HASH}

algorithm_option
    ALGORITHM [=] {DEFAULT | INPLACE | 复制}

lock_option
    LOCK [=] {DEFAULT | 没有| 共享| 独家}

通常,您在创建表本身时在表上创建所有索引 CREATE TABLE 请参见 第13.1.20节“CREATE TABLE语法” 对于 InnoDB 表,其中主键确定数据文件中行的物理布局, 此指南尤其重要 CREATE INDEX 使您可以向现有表添加索引。

CREATE INDEX 映射到一个 ALTER TABLE 语句来创建索引。 请参见 第13.1.9节“ALTER TABLE语法” CREATE INDEX 不能用来创造 PRIMARY KEY ; 使用 ALTER TABLE 来代替。 有关索引的更多信息,请参见 第8.3.1节“MySQL如何使用索引”

InnoDB 支持虚拟列上的二级索引。 有关更多信息,请参见 第13.1.20.10节“二级索引和生成的列”

innodb_stats_persistent 启用 设置 后,在该表上创建索引后 运行 ANALYZE TABLE 语句 InnoDB

表单的索引规范 创建具有多个关键部分的索引。 索引键值是通过连接给定关键部分的值而形成的。 例如 指定与由索引关键字值从多列索引 (key_part1, key_part2, ...) (col1, col2, col3) col1 col2 col3

key_part 规格可以与结束 ASC DESC 以指定的索引值是否被存储在升序或降序。 如果未给出订单说明符,则默认值为升序。 ASC 并且 DESC 不允许 HASH 索引。 在MySQL 8.0.12的, ASC DESC 不是允许 SPATIAL 索引。

以下部分描述了该 CREATE INDEX 语句的 不同方面

列前缀键部件

对于字符串列,可以创建仅使用列值的前导部分 的索引 ,使用 语法指定索引前缀长度: col_name(length)

如果指定的索引前缀超过最大列数据类型大小, CREATE INDEX 则按如下方式处理索引:

  • 对于非唯一索引,要么发生错误(如果启用了严格的SQL模式),要么索引长度减少到最大列数据类型大小,并产生警告(如果未启用严格SQL模式)。

  • 对于唯一索引,无论SQL模式如何都会发生错误,因为减少索引长度可能会导致插入不符合指定唯一性要求的非唯一条目。

此处显示的语句使用列的前10个字符创建索引 name (假设它 name 具有非二进制字符串类型):

CREATE INDEX part_of_name ON customer(name(10));

如果列中的名称通常在前10个字符中不同,则使用此索引执行的查找不应比使用从整个 name 创建的索引慢得多 此外,使用索引的列前缀可以使索引文件更小,这可以节省大量磁盘空间并且还可以加快 INSERT 操作。

功能关键部件

正常 索引索引列值或者列值的前缀。 例如,在下表中,给定 t1 的索引条目 包括完整 col1 值和 col2 由前10个字符组成的 值的前缀

CREATE TABLE t1(
  col1 VARCHAR(10),
  col2 VARCHAR(20),
  INDEX(col1,col2(10))
);

MySQL 8.0.13及更高版本支持索引表达式值而不是列或列前缀值的功能键部分。 使用功能键部件可以索引未直接存储在表中的值。 例子:

CREATE TABLE t1(col1 INT,col2 INT,INDEX func_index((ABS(col1))));
CREATE INDEX idx1 ON t1((col1 + col2));
CREATE INDEX idx2 ON t1((col1 + col2),(col1-col2),col1);
ALTER TABLE t1 ADD INDEX((col1 * 40)DESC);

具有多个关键部分的索引可以混合非功能和功能关键部分。

ASC DESC 支持功能关键部件。

功能关键部件必须遵守以下规则。 如果关键部件定义包含不允许的构造,则会发生错误。

  • 在索引定义中,将表达式括在括号内,以将它们与列或列前缀区分开来。 例如,这是允许的; 表达式括在括号内:

    INDEX((col1 + col2),(col3-col4))
    

    这会产生错误; 表达式不包含在括号内:

    INDEX(col1 + col2,col3  -  col4)
    
  • 功能键部分不能仅由列名组成。 例如,这是不允许的:

    INDEX((col1),(col2))
    

    相反,将关键部分写为非功能性关键部分,不带括号:

    INDEX(col1,col2)
    
  • 功能键部分表达式不能引用列前缀。 有关解决方法,请参阅的讨论 SUBSTRING() ,并 CAST() 在本节后面。

  • 外键规范中不允许使用功能关键部件。

对于 CREATE TABLE ... LIKE ,目标表保留原始表中的功能键部分。

功能索引实现为隐藏的虚拟生成列,具有以下含义:

UNIQUE 支持包含功能键部分的索引。 但是,主键不能包含功能键部分。 主键需要存储生成的列,但功能键部分实现为虚拟生成列,而不是存储生成列。

SPATIAL FULLTEXT 索引不能有功能关键部分。

如果表中不包含主键, InnoDB 则会自动将第一个 UNIQUE NOT NULL 索引提升为主键。 UNIQUE NOT NULL 具有功能键部分的索引 不支持此 功能。

如果存在重复索引,则非功能性索引会发出警告。 包含功能键部件的索引没有此功能。

要删除功能键部件引用的列,必须首先删除索引。 否则,会发生错误。

虽然非功能性关键部件支持前缀长度规范,但这对于功能关键部件是不可能的。 解决方案是使用 SUBSTRING() (或 CAST() ,如本节后面所述)。 对于包含 SUBSTRING() 要在查询中使用 函数 的功能键部分 ,该 WHERE 子句必须包含 SUBSTRING() 相同的参数。 在以下示例中,只有第二个 SELECT 能够使用索引,因为这是 SUBSTRING() 与索引规范匹配的 参数的唯一查询

CREATE TABLE tbl(
  col1 LONGTEXT,
  INDEX idx1((SUBSTRING(col1,1,10)))
);
SELECT * FROM tbl WHERE SUBSTRING(col1,1,9)='123456789';
SELECT * FROM tbl WHERE SUBSTRING(col1,1,10)='1234567890';

功能键部件支持索引无法索引的值,例如 JSON 值。 但是,必须正确地完成这一操作才能达到预期的效果。 例如,此语法不起作用:

CREATE TABLE员工(
  数据JSON,
  INDEX((data  -  >>'$。name'))
);

语法失败,因为:

要索引 JSON 列,您可以尝试使用以下 CAST() 函数:

CREATE TABLE员工(
  数据JSON,
  INDEX((CAST(data  -  >>'$。name'AS CHAR(30))))
);

为隐藏的生成列分配 VARCHAR(30) 数据类型,可以对其进行索引。 但是这种方法在尝试使用索引时会产生一个新问题:

  • CAST() 返回带有排序规则的字符串 utf8mb4_0900_ai_ci (服务器默认排序规则)。

  • JSON_UNQUOTE() 返回带有排序规则的字符串 utf8mb4_bin (硬编码)。

因此,前面的表定义中的索引表达式 WHERE 与以下查询中 子句表达式 之间存在排序规则不匹配

SELECT * FROM employees WHERE data  -  >>'$。name'='James';

不使用索引,因为查询中的表达式和索引不同。 为了支持这种方案的功能键部分,优化自动去除 CAST() 寻找一个指数时使用,但 只有 当索引表达式的排序规则匹配查询表达式。 对于具有要使用的功能键部分的索引,以下两个解决方案中的任何一个都有效(尽管它们在某种程度上有所不同):

  • 解决方案1.为索引表达式分配相同的排序规则 JSON_UNQUOTE()

    CREATE TABLE员工(
      数据JSON,
      INDEX idx((CAST(data  -  >>“$。name”AS CHAR(30))COLLATE utf8mb4_bin))
    );
    插入员工价值观
      ('{“name”:“james”,“salary”:9000}'),
      ('{“name”:“詹姆斯”,“薪水”:10000}'),
      ('{“name”:“Mary”,“salary”:12000}'),
      ('{“name”:“Peter”,“salary”:8000}');
    SELECT * FROM employees WHERE data  -  >>'$。name'='James';
    

    ->> 操作是一样的 JSON_UNQUOTE(JSON_EXTRACT(...)) ,并 JSON_UNQUOTE() 返回与归类的字符串 utf8mb4_bin 因此,比较区分大小写,只有一行匹配:

    + ------------------------------------ +
    | 数据|
    + ------------------------------------ +
    | {“name”:“James”,“薪水”:10000} |
    + ------------------------------------ +
    
  • 解决方案2.在查询中指定完整表达式:

    CREATE TABLE员工(
      数据JSON,
      INDEX idx((CAST(data  -  >>“$。name”AS CHAR(30))))
    );
    插入员工价值观
      ('{“name”:“james”,“salary”:9000}'),
      ('{“name”:“詹姆斯”,“薪水”:10000}'),
      ('{“name”:“Mary”,“salary”:12000}'),
      ('{“name”:“Peter”,“salary”:8000}');
    SELECT * FROM employees WHERE CAST(data  -  >>'$。name'AS CHAR(30))='James';
    

    CAST() 返回带有排序规则的字符串 utf8mb4_0900_ai_ci ,因此比较不区分大小写且两行匹配:

    + ------------------------------------ +
    | 数据|
    + ------------------------------------ +
    | {“name”:“james”,“salary”:9000} |
    | {“name”:“James”,“薪水”:10000} |
    + ------------------------------------ +
    

请注意,尽管优化程序支持 CAST() 使用索引生成的列 自动剥离 ,但以下方法不起作用,因为它会生成带有和不带索引的不同结果(Bug#27337092):

MySQL的> CREATE TABLE employees (
         data JSON,
         generated_col VARCHAR(30) AS (CAST(data->>'$.name' AS CHAR(30)))
       );
查询正常,0行受影响,1警告(0.03秒)

MySQL的> INSERT INTO employees (data)
       VALUES ('{"name": "james"}'), ('{"name": "James"}');
查询正常,2行受影响,1警告(0.01秒)
记录:2个重复:0警告:1

MySQL的> SELECT * FROM employees WHERE data->>'$.name' = 'James';
+ ------------------- + --------------- +
| 数据| generated_col |
+ ------------------- + --------------- +
| {“name”:“James”} | 詹姆斯|
+ ------------------- + --------------- +
1排(0.00秒)

MySQL的> ALTER TABLE employees ADD INDEX idx (generated_col);
查询正常,0行受影响,1警告(0.03秒)
记录:0重复:0警告:1

MySQL的> SELECT * FROM employees WHERE data->>'$.name' = 'James';
+ ------------------- + --------------- +
| 数据| generated_col |
+ ------------------- + --------------- +
| {“name”:“james”} | 詹姆斯|
| {“name”:“James”} | 詹姆斯|
+ ------------------- + --------------- +
2行(0.01秒)

独特的索引

一个 UNIQUE 索引创建的约束,使得该指数的所有值必须是不同的。 如果您尝试添加具有与现有行匹配的键值的新行,则会发生错误。 如果为 UNIQUE 索引中的列 指定前缀值 ,则列值必须在前缀长度内是唯一的。 一个 UNIQUE 索引,可以多次 NULL 进行,可以包含列的值 NULL

如果表具有 由具有整数类型的单个列组成的索引 PRIMARY KEY UNIQUE NOT NULL 索引,则可以使用它 _rowid 来引用 SELECT 语句中 的索引列 ,如下所示:

  • _rowid PRIMARY KEY 如果存在 PRIMARY KEY 由单个整数列组成 列,则 引用该 列。 如果有, PRIMARY KEY 但它不包含单个整数列, _rowid 则不能使用。

  • 否则, 如果该索引由单个整数列组成 ,则 _rowid 引用第一个 UNIQUE NOT NULL 索引中的列。 如果第一个 UNIQUE NOT NULL 索引不包含单个整数列, _rowid 则不能使用。

全文索引

FULLTEXT 索引仅支持 InnoDB MyISAM 表格,并且可以只包括 CHAR VARCHAR TEXT 列。 索引总是发生在整个列上; 不支持列前缀索引,如果指定,则忽略任何前缀长度。 有关 操作的详细信息, 请参见 第12.9节“全文搜索功能”

空间索引

MyISAM InnoDB NDB ,和 ARCHIVE 存储引擎支持空间列,比如 POINT GEOMETRY 第11.5节“空间数据类型” 描述了空间数据类型。)但是,空间列索引的支持因引擎而异。 根据以下规则,空间列上的空间和非空间索引可用。

空间列上的空间索引具有以下特征:

  • 仅适用于 InnoDB MyISAM 表格。 指定 SPATIAL INDEX 其他存储引擎会导致错误。

  • 从MySQL 8.0.12开始,空间列 索引 必须 SPATIAL 索引。 因此, SPATIAL 关键字是可选的,但隐含用于在空间列上创建索引。

  • 仅适用于单个空间列。 无法在多个空间列上创建空间索引。

  • 索引列必须是 NOT NULL

  • 列前缀长度是禁止的。 索引每列的全宽。

  • 不允许使用主键或唯一索引。

在空间列非空间索引(与创建 INDEX UNIQUE PRIMARY KEY )具有以下特征:

  • 允许任何支持空间列的存储引擎除外 ARCHIVE

  • NULL 除非索引是主键,否则 列可以是列

  • SPATIAL 索引 的索引类型 取决于存储引擎。 目前,使用B树。

  • 允许,可以有一个列 NULL 仅值 InnoDB MyISAM MEMORY 表。

指数期权

在关键部件列表之后,可以给出索引选项。 index_option 值可以是任何以下的:

  • KEY_BLOCK_SIZE [=] value

    对于 MyISAM 表, KEY_BLOCK_SIZE 可以选择指定用于索引键块的大小(以字节为单位)。 该值被视为提示; 如有必要,可以使用不同的尺寸。 KEY_BLOCK_SIZE 为单个索引定义指定 值将覆盖表级 KEY_BLOCK_SIZE 值。

    KEY_BLOCK_SIZE InnoDB 的索引级别不支持 请参见 第13.1.20节“CREATE TABLE语法”

  • index_type

    某些存储引擎允许您在创建索引时指定索引类型。 例如:

    CREATE TABLE查找(id INT)ENGINE = MEMORY;
    CREATE INDEX id_index ON lookup(id)USING BTREE;
    

    表13.1“每个存储引擎的索引类型” 显示了不同存储引擎支持的允许索引类型值。 如果列出了多个索引类型,则在没有给出索引类型说明符时,第一个是缺省值。 表中未列出的存储引擎不支持 index_type 索引定义中 子句。

    表13.1每个存储引擎的索引类型

    存储引擎 允许的索引类型
    InnoDB BTREE
    MyISAM BTREE
    MEMORY / HEAP HASH BTREE
    NDB HASH BTREE (见文中注释)

    index_type 子句不能用于 FULLTEXT INDEX 或(在MySQL 8.0.12之前) SPATIAL INDEX 规范。 全文索引实现依赖于存储引擎。 空间索引实现为R树索引。

    如果指定的索引类型对于给定的存储引擎无效,但引擎可以使用另一种索引类型而不影响查询结果,则引擎将使用可用类型。 解析器识别 RTREE 为类型名称。 从MySQL 8.0.12开始,仅允许 SPATIAL 索引使用。 在8.0.12之前, RTREE 无法为任何存储引擎指定。

    BTREE 索引由 NDB 存储引擎实现为T树索引。

    注意

    对于 NDB 表列的 索引 USING 只能为唯一索引或主键指定 选项。 USING HASH 阻止创建有序索引; 否则,在 NDB 上创建唯一索引或主键会 自动导致创建有序索引和散列索引,每个索引都对同一列索引进行索引。

    对于包含 NULL 表的一列 或多 列的 唯一索引, NDB 哈希索引只能用于查找文字值,这意味着 IS [NOT] NULL 条件需要对表进行完整扫描。 一种解决方法是确保 NULL 在这样的表上 使用一个或多个 的唯一索引 始终以包含有序索引的方式创建; 也就是说,避免 USING HASH 在创建索引时使用。

    如果指定的索引类型对于给定的存储引擎无效,但引擎可以使用另一种索引类型而不影响查询结果,则引擎将使用可用类型。 解析器识别 RTREE 为类型名称,但目前无法为任何存储引擎指定。

    注意

    index_type 不推荐使用 子句 之前 使用该 选项 ; 在将来的MySQL版本中将删除对此位置中选项的使用的支持。 如果 在较早和较晚的位置都给出了 一个 选项,则最终选项适用。 ON tbl_name index_type

    TYPE type_name 被认为是的同义词 但是, 是首选形式。 USING type_name USING

    下表显示了支持该 index_type 选项 的存储引擎的索引特征

    表13.2 InnoDB存储引擎索引特征

    指数类 索引类型 存储NULL值 允许多个NULL值 IS NULL扫描类型 IS NOT NULL扫描类型
    首要的关键 BTREE 没有 没有 N / A N / A
    独特 BTREE 指数 指数
    BTREE 指数 指数
    FULLTEXT N / A
    SPATIAL N / A 没有 没有 N / A N / A

    表13.3 MyISAM存储引擎索引特征

    指数类 索引类型 存储NULL值 允许多个NULL值 IS NULL扫描类型 IS NOT NULL扫描类型
    首要的关键 BTREE 没有 没有 N / A N / A
    独特 BTREE 指数 指数
    BTREE 指数 指数
    FULLTEXT N / A
    SPATIAL N / A 没有 没有 N / A N / A

    表13.4 MEMORY存储引擎索引特征

    指数类 索引类型 存储NULL值 允许多个NULL值 IS NULL扫描类型 IS NOT NULL扫描类型
    首要的关键 BTREE 没有 没有 N / A N / A
    独特 BTREE 指数 指数
    BTREE 指数 指数
    首要的关键 HASH 没有 没有 N / A N / A
    独特 HASH 指数 指数
    HASH 指数 指数

    表13.5 NDB存储引擎索引特征

    指数类 索引类型 存储NULL值 允许多个NULL值 IS NULL扫描类型 IS NOT NULL扫描类型
    首要的关键 BTREE 没有 没有 指数 指数
    独特 BTREE 指数 指数
    BTREE 指数 指数
    首要的关键 HASH 没有 没有 表(见注1) 表(见注1)
    独特 HASH 表(见注1) 表(见注1)
    HASH 表(见注1) 表(见注1)

    表注意:

    1. USING HASH 阻止创建隐式有序索引。

  • WITH PARSER parser_name

    此选项只能用于 FULLTEXT 索引。 如果全文索引和搜索操作需要特殊处理,它会将解析器插件与索引相关联。 InnoDB MyISAM 支持全文解析器插件。 有关详细信息,请参阅 全文分析器插件 第29.2.4.4节“编写全文分析器插件”

  • COMMENT 'string'

    索引定义可以包含最多1024个字符的可选注释。

    MERGE_THRESHOLD 索引页面可以被配置为使用单独的索引 中的条款 声明。 例如: index_option COMMENT CREATE INDEX

    CREATE TABLE t1(id INT);
    CREATE INDEX id_index ON t1(id)COMMENT'MERGE_THRESHOLD = 40';
    

    如果索引页的页面满百分比低于 MERGE_THRESHOLD 删除行时或更新操作缩短行时 值,则 InnoDB 尝试将索引页与相邻索引页合并。 默认 MERGE_THRESHOLD 值为50,这是以前的硬编码值。

    MERGE_THRESHOLD 也可以使用 CREATE TABLE ALTER TABLE 语句 在索引级别和表级别定义 有关更多信息,请参见 第15.8.11节“配置索引页的合并阈值”

  • VISIBLE INVISIBLE

    指定索引可见性。 默认情况下,索引是可见的。 优化程序不使用不可见索引。 索引可见性的规范适用于除主键之外的索引(显式或隐式)。 有关更多信息,请参见 第8.3.12节“不可见索引”

表复制和锁定选项

ALGORITHM 并且 LOCK 可以赋予子句以影响表复制方法和在修改索引时读写表的并发级别。 它们与 ALTER TABLE 声明 具有相同的含义 有关更多信息,请参见 第13.1.9节“ALTER TABLE语法”

NDB Cluster ALGORITHM=INPLACE 使用与标准MySQL服务器 相同的 语法 支持在线操作 有关 更多信息 请参见 第22.5.14节“使用NDB簇中的ALTER TABLE进行联机操作”

13.1.16 CREATE LOGFILE GROUP语法

CREATE LOGFILE GROUP logfile_group
    ADD UNDOFILE' undo_file'
    [INITIAL_SIZE [=] initial_size]
    [UNDO_BUFFER_SIZE [=] undo_buffer_size]
    [REDO_BUFFER_SIZE [=] redo_buffer_size]
    [NODEGROUP [=] nodegroup_id]
    [等待]
    [评论[=]'string ']
    发动机[=] engine_name

此语句创建一个 名为“ logfile_group 的单个 UNDO 文件 的新日志文件组 undo_file 一个 CREATE LOGFILE GROUP 语句有一个且只有一个 ADD UNDOFILE 条款。 有关日志文件组命名的规则,请参见 第9.2节“架构对象名称”

注意

所有NDB Cluster Disk Data对象共享相同的命名空间。 这意味着 必须唯一地命名 每个磁盘数据对象 (而不仅仅是给定类型的每个磁盘数据对象)。 例如,您不能拥有具有相同名称的表空间和日志文件组,或者具有相同名称的表空间和数据文件。

在任何给定时间,每个NDB群集实例只能有一个日志文件组。

可选 INITIAL_SIZE 参数设置 UNDO 文件的初始大小; 如果未指定,则默认为 128M (128兆字节)。 可选 UNDO_BUFFER_SIZE 参数设置 UNDO 缓冲区用于日志文件组的大小; 其缺省值 UNDO_BUFFER_SIZE 8M (8兆字节); 此值不能超过可用的系统内存量。 这两个参数都以字节为单位指定。 您可以选择使用一个字母的缩写来跟随其中一个或两个,其数量级类似于 my.cnf 通常,这是字母之一 M (兆字节)或 G (千兆字节)。

用于的内存 UNDO_BUFFER_SIZE 来自全局池,其大小由 SharedGlobalMemory 数据节点配置参数 的值确定 这包括通过设置 InitialLogFileGroup 数据节点配置参数 对此选项隐含的任何默认值

允许的最大值为 UNDO_BUFFER_SIZE 629145600(600 MB)。

在32位系统上,支持的最大值为 INITIAL_SIZE 4294967296(4 GB)。 (Bug#29186)

允许的最小值为 INITIAL_SIZE 1048576(1 MB)。

ENGINE 选项确定此日志文件组要使用 engine_name 的存储引擎,该存储引擎是存储引擎的名称。 在MySQL 8.0中,这必须是 NDB (或 NDBCLUSTER )。 如果 ENGINE 未设置,MySQL将尝试使用 default_storage_engine 服务器系统变量(以前 storage_engine 指定的引擎 在任何情况下,如果引擎未指定为 NDB or NDBCLUSTER ,则该 CREATE LOGFILE GROUP 语句似乎成功但实际上无法创建日志文件组,如下所示:

mysql> CREATE LOGFILE GROUP lg1
    - >     ADD UNDOFILE 'undo.dat' INITIAL_SIZE = 10M;
查询正常,0行受影响,1警告(0.00秒)

MySQL的> SHOW WARNINGS;
+ ------- + ------ + ---------------------------------- -------------------------------------------------- ------------ +
| 等级| 代码| 消息|
+ ------- + ------ + ---------------------------------- -------------------------------------------------- ------------ +
| 错误| 1478 | 表存储引擎'InnoDB'不支持创建选项'TABLESPACE或LOGFILE GROUP' |
+ ------- + ------ + ---------------------------------- -------------------------------------------------- ------------ +
1排(0.00秒)

mysql> ERROR 1529(HY000):无法删除LOGFILE GROUPDROP LOGFILE GROUP lg1 ENGINE = NDB;            


mysql> CREATE LOGFILE GROUP lg1
    - >      ADD UNDOFILE 'undo.dat' INITIAL_SIZE = 10M
    - >     ENGINE = NDB;
查询OK,0行受影响(2.97秒)

CREATE LOGFILE GROUP 当一个非 NDB 存储引擎被命名,但似乎成功 ,该 语句实际上没有返回错误 这一事实 是我们希望在未来的NDB Cluster版本中解决的一个已知问题。

REDO_BUFFER_SIZE NODEGROUP WAIT ,和 COMMENT 被分析,但是被忽略,所以有在MySQL 8.0没有影响。 这些选项旨在用于将来的扩展。

使用时 ENGINE [=] NDB UNDO 会在每个群集数据节点上创建 日志文件组和关联的 日志文件。 您可以 UNDO 通过查询 INFORMATION_SCHEMA.FILES 来验证 文件是否已创建并获取有关它们的信息 例如:

mysql> SELECT LOGFILE_GROUP_NAME, LOGFILE_GROUP_NUMBER, EXTRA
    - > FROM INFORMATION_SCHEMA.FILES
    - >WHERE FILE_NAME = 'undo_10.dat';
+ -------------------- + ---------------------- + ----- ----------- +
| LOGFILE_GROUP_NAME | LOGFILE_GROUP_NUMBER | 额外|
+ -------------------- + ---------------------- + ----- ----------- +
| lg_3 | 11 | CLUSTER_NODE = 3 |
| lg_3 | 11 | CLUSTER_NODE = 4 |
+ -------------------- + ---------------------- + ----- ----------- +
2行(0.06秒)

CREATE LOGFILE GROUP 仅适用于NDB Cluster的磁盘数据存储。 请参见 第22.5.13节“NDB集群磁盘数据表”

13.1.17创建过程和创建函数语法

创建
    [DEFINER = user]
    程序sp_name([ proc_parameter[,...]])
    [ characteristic...]routine_body

创建
    [DEFINER = user]
    功能sp_name([ func_parameter[,...]])
    退货type
    [ characteristic...]routine_body

proc_parameter
    [IN | OUT | 进出 ]param_name type

func_parameterparam_name type

typeAny valid MySQL data type

characteristic
    评论' string'
  | 语言SQL
  | [NOT]决定因素
  | {包含SQL | 没有SQL | 读取SQL数据| 修改SQL DATA}
  | SQL SECURITY {DEFINER | INVOKER}

routine_bodyValid SQL routine statement

这些语句创建存储的例程。 默认情况下,例程与默认数据库关联。 要将例程与给定数据库显式关联,请 db_name.sp_name 在创建时 指定名称

CREATE FUNCTION 语句还在MySQL中用于支持UDF(用户定义的函数)。 请参见 第29.4节“向MySQL添加新函数” UDF可以被视为外部存储功能。 存储函数与UDF共享其命名空间。 有关 描述服务器如何解释对不同类型函数的引用的规则 请参见 第9.2.4节“函数名称解析和解析”

要调用存储过程,请使用该 CALL 语句(请参见 第13.2.1节“CALL语法” )。 要调用存储的函数,请在表达式中引用它。 该函数在表达式求值期间返回一个值。

CREATE PROCEDURE CREATE FUNCTION 要求 CREATE ROUTINE 特权。 如果该 DEFINER 子句存在,则所需的权限取决于 user 值,如 第24.6节“存储对象访问控制”中所述 如果启用了二进制日志记录,则 CREATE FUNCTION 可能需要该 SUPER 特权,如 第24.7节“存储程序二进制日志记录”中所述

默认情况下,MySQL的自动授权 ALTER ROUTINE EXECUTE 权限,以常规的创造者。 可以通过禁用 automatic_sp_privileges 系统变量 来更改此行为 请参见 第24.2.2节“存储例程和MySQL特权”

DEFINER SQL SECURITY 子句指定的安全上下文,在程序执行时检查访问权限的情况下,如在本节后面所述使用。

如果例程名称与内置SQL函数的名称相同,则会发生语法错误,除非在定义例程或稍后调用例程时在名称和以下括号之间使用空格。 因此,请避免将现有SQL函数的名称用于您自己的存储例程。

IGNORE_SPACE SQL模式适用于内置的功能,而不是保存的程序。 无论是否 IGNORE_SPACE 启用 ,始终允许在存储的例程名称后面有空格

括号内的参数列表必须始终存在。 如果没有参数, () 则应使用 空参数列表 参数名称不区分大小写。

IN 默认情况下, 每个参数都是 参数。 要为参数指定其他方式,请使用关键字 OUT INOUT 参数名称之前。

注意

将参数指定为 IN OUT INOUT 仅对a有效 PROCEDURE 对于a FUNCTION ,参数始终被视为 IN 参数。

一个 IN 参数传送一个值的过程。 该过程可能会修改该值,但过程返回时调用程序看不到修改。 一个 OUT 参数传送从过程返回给调用者的值。 它的初始值 NULL 在过程中,当过程返回时,调用者可以看到它的值。 一个 INOUT 参数是由呼叫者初始化,可以由程序进行修改,并且由所述方法制备的任何变化是可见的呼叫者时,过程返回。

对于每个 OUT INOUT 参数,在 CALL 调用过程 语句中 传递用户定义的变量, 以便在过程返回时获取其值。 如果要调用从另一个存储过程或函数内的过程中,你也可以通过常规的参数或局部常规变量作为 OUT INOUT 参数。 如果要调用从一个触发器中的过程中,你也可以通过 作为 参数。 NEW.col_name OUT INOUT

有关未处理条件对过程参数的影响的信息,请参见 第13.6.7.8节“条件处理和OUT或INOUT参数”

在例程中准备的语句中不能引用例程参数; 请参见 第C.1节“存储程序的限制”

以下示例显示了一个使用 OUT 参数 的简单存储过程

MySQL的> delimiter //

mysql> CREATE PROCEDURE simpleproc (OUT param1 INT)
    - > BEGIN
    - >    SELECT COUNT(*) INTO param1 FROM t;
    - >END//
查询正常,0行受影响(0.00秒)

MySQL的> delimiter ;

MySQL的> CALL simpleproc(@a);
查询正常,0行受影响(0.00秒)

MySQL的> SELECT @a;
+ ------ +
| @a |
+ ------ +
| 3 |
+ ------ +
1排(0.00秒)

该示例使用 MySQL的 客户机 delimiter 命令语句从定界符改变 ; // 当正在定义的过程。 这使得 ; 过程体中使用 分隔符能够传递到服务器,而不是由 mysql 本身 解释 请参见 第24.1节“定义存储的程序”

RETURNS 条款只能为a FUNCTION 强制规定。 它表示函数的返回类型,函数体必须包含一个 语句。 如果 语句返回不同类型的值,则将该值强制转换为正确的类型。 例如,如果函数 子句中 指定了一个 ,但该 语句返回一个整数,则该函数返回的值是 成员集 的相应 成员 的字符串 RETURN value RETURN ENUM SET RETURNS RETURN ENUM SET

以下示例函数接受一个参数,使用SQL函数执行操作,并返回结果。 在这种情况下,不必使用, delimiter 因为函数定义不包含内部 ; 语句分隔符:

mysql> CREATE FUNCTION hello (s CHAR(20))
mysql> RETURNS CHAR(50) DETERMINISTIC
    - >RETURN CONCAT('Hello, ',s,'!');
查询正常,0行受影响(0.00秒)

MySQL的> SELECT hello('world');
+ ---------------- +
| 你好('世界')|
+ ---------------- +
| 你好,世界!|
+ ---------------- +
1排(0.00秒)

可以声明参数类型和函数返回类型以使用任何有效的数据类型。 COLLATE 如果前面有 CHARACTER SET 规范, 则可以使用 属性

routine_body 由一个有效的SQL例程语句组成。 这可以是一个简单的语句,如 SELECT or INSERT ,或者是使用 BEGIN 编写的复合语句 END 复合语句可以包含声明,循环和其他控制结构语句。 第13.6节“复合语句语法”中 描述了这些语句的 语法 实际上,存储函数倾向于使用复合语句,除非正文包含单个 RETURN 语句。

MySQL允许例程包含DDL语句,例如 CREATE DROP MySQL还允许存储过程(但不是存储函数)包含SQL事务语句,如 COMMIT 存储的函数可能不包含执行显式或隐式提交或回滚的语句。 SQL标准不要求支持这些语句,该标准规定每个DBMS供应商可以决定是否允许它们。

返回结果集的语句可以在存储过程中使用,但不能在存储的函数中使用。 这项禁令包括 SELECT 不具有的声明 条款等语句,如 对于可以在函数定义时确定以返回结果集的语句,会 发生错误( )。 对于只能在运行时确定以返回结果集的语句,会 发生错误( )。 INTO var_list SHOW EXPLAIN CHECK TABLE Not allowed to return a result set from a function ER_SP_NO_RETSET PROCEDURE %s can't return a result set in the given context ER_SP_BADSELECT

USE 不允许存储例程中的语句。 调用例程时,将 执行 隐式 (并在例程终止时撤消)。 导致例程在执行时具有给定的默认数据库。 应使用适当的数据库名称限定对除例程缺省数据库之外的数据库中的对象的引用。 USE db_name

有关存储例程中不允许的语句的其他信息,请参见 第C.1节“存储程序的限制”

有关从具有MySQL接口的语言编写的程序中调用存储过程的信息,请参见 第13.2.1节“CALL语法”

MySQL sql_mode 在创建或更改例程时 存储有效的 系统变量设置,并始终使用此设置执行例程, 而不管例程开始执行时当前服务器SQL模式如何

在评估参数并将结果值分配给例程参数之后,将从调用者的SQL模式切换到例程的SQL模式。 如果在严格SQL模式下定义例程但在非严格模式下调用它,则不会在严格模式下为常规参数分配参数。 如果要求在严格SQL模式下分配传递给例程的表达式,则应调用具有严格模式的例程。

COMMENT 特性是MySQL扩展,可用于描述存储的例程。 此信息由 SHOW CREATE PROCEDURE SHOW CREATE FUNCTION 语句 显示

LANGUAGE 特性表示其中例行程序语言编写。 服务器忽略了这个特性; 仅支持SQL例程。

的例程被认为是 确定性的 ,如果它总是产生相同的结果对于相同的输入参数,并且 不确定性 否则。 如果 例程定义中 既未 给出 DETERMINISTIC NOT DETERMINISTIC 给出,则默认为 NOT DETERMINISTIC 要声明函数是确定性的,必须 DETERMINISTIC 明确 指定

对例程性质的评估基于 创建者 诚实 :MySQL不会检查声明的例程 DETERMINISTIC 是否没有产生非确定性结果的语句。 但是,错误地说明例程可能会影响结果或影响性能。 声明非确定性例程 DETERMINISTIC 可能会导致优化程序选择错误的执行计划,从而导致意外结果。 声明确定性例程 NONDETERMINISTIC 可能会导致不使用可用的优化,从而降低性能。

如果启用了二进制日志记录,则该 DETERMINISTIC 特性会影响MySQL接受的例程定义。 请参见 第24.7节“存储程序二进制日志记录”

包含 NOW() 函数(或其同义词)或 RAND() 不确定 的例程 ,但它可能仍然是复制安全的。 对于 NOW() ,二进制日志包括时间戳并正确复制。 RAND() 只要在执行例程期间只调用一次,也可以正确复制。 (您可以将例程执行时间戳和随机数种子视为主服务器和从服务器上相同的隐式输入。)

几个特征提供了关于例程使用数据的性质的信息。 在MySQL中,这些特征仅供参考。 服务器不使用它们来约束允许例程执行的语句类型。

  • CONTAINS SQL 表示该例程不包含读取或写入数据的语句。 如果没有明确给出这些特征,则这是默认值。 这些语句的例子是 SET @x = 1 或者 DO RELEASE_LOCK('abc') ,它们既可以执行但不能读取或写入数据。

  • NO SQL 表示该例程不包含SQL语句。

  • READS SQL DATA 表示例程包含读取数据的语句(例如 SELECT ),但不包含写入数据的语句。

  • MODIFIES SQL DATA 表示该例程包含可能写入数据的语句(例如, INSERT DELETE )。

所述 SQL SECURITY 特性可以是 DEFINER INVOKER 以指定的安全上下文; 也就是说,例程是使用例程 DEFINER 子句中 指定的帐户的权限 还是使用调用它的用户执行。 此帐户必须具有访问与例程关联的数据库的权限。 默认值为 DEFINER 调用例程的用户必须拥有该 EXECUTE 特权, DEFINER 如果例程在definer安全上下文中执行,则 必须具有该 帐户 特权

DEFINER 子句指定在常规执行时检查具有该 SQL SECURITY DEFINER 特征的 例程的访问权限时要使用的MySQL帐户

如果 DEFINER 子句,该 user 值应被指定为一个MySQL帐户 允许的 值取决于您拥有的权限,如 第24.6节“存储对象访问控制”中所述 有关存储的例程安全性的其他信息,另请参阅该部分。 'user_name'@'host_name' CURRENT_USER CURRENT_USER() user

如果 DEFINER 省略 子句,则默认定义者是执行 CREATE PROCEDURE or CREATE FUNCTION 语句 的用户 这与 DEFINER = CURRENT_USER 明确 指定相同

在使用 SQL SECURITY DEFINER 特征 定义的存储例程的主体内 ,该 CURRENT_USER 函数返回例程的 DEFINER 值。 有关存储例程中的用户审计的信息,请参见 第6.2.22节“基于SQL的帐户活动审计”

请考虑以下过程,该过程显示 mysql.user 系统表中 列出的MySQL帐户数量的计数

CREATE DEFINER ='admin'@'localhost'PROCEDURE account_count()
开始
  SELECT'帐号数:',COUNT(*)FROM mysql.user;
结束;

无论哪个用户定义 该过程,都会为该过程分配 DEFINER 帐户 'admin'@'localhost' 无论哪个用户调用它,它都以该帐户的权限执行(因为默认的安全特性是 DEFINER )。 该过程成功或失败取决于调用者是否具有该 EXECUTE 特权并 'admin'@'localhost' 具有 SELECT mysql.user 特权

现在假设该过程是使用以下 SQL SECURITY INVOKER 特征 定义的

CREATE DEFINER ='admin'@'localhost'PROCEDURE account_count()
SQL安全调查员
开始
  SELECT'帐号数:',COUNT(*)FROM mysql.user;
结束;

该过程仍具有 DEFINER 'admin'@'localhost' ,但在这种情况下,它与调用用户的权限执行。 因此,该过程成功或失败取决于调用者是否具有该 EXECUTE 特权以及 SELECT mysql.user 特权

服务器处理例程参数的数据类型,使用 DECLARE 或函数返回值 创建的本地例程变量 ,如下所示:

  • 检查分配的数据类型不匹配和溢出。 转换和溢出问题会导致警告或严格SQL模式中的错误。

  • 只能分配标量值。 例如,诸如 SET x = (SELECT 1, 2) 无效 的陈述

  • 对于字符数据类型,if CHARACTER SET 包含在声明中,使用指定的字符集及其默认排序规则。 如果该 COLLATE 属性也存在,则使用该排序规则而不是默认排序规则。

    如果 CHARACTER SET COLLATE 不存在,则使用在例程创建时有效的数据库字符集和排序规则。 为避免服务器使用数据库字符集和排序规则,请 为字符数据参数 提供显式 CHARACTER SET COLLATE 属性。

    如果更改数据库缺省字符集或排序规则,则必须删除并重新创建使用数据库缺省值的存储例程,以便它们使用新的缺省值。

    该数据库字符集和校对规则由的值给出 character_set_database collation_database 系统变量。 有关更多信息,请参见 第10.3.3节“数据库字符集和排序规则”

13.1.18 CREATE SERVER语法

创建服务器server_name
    外部数据包装wrapper_name
    选项(option[,option] ...)

option
  {主持人character-literal
  | 数据库character-literal
  | 用户character-literal
  | 密码character-literal
  | SOCKET character-literal
  | 所有者character-literal
  | PORT numeric-literal}

此语句创建用于 FEDERATED 存储引擎 的服务器的定义 CREATE SERVER 语句 servers mysql 数据库 表中 创建一个新行 此声明需要该 SUPER 权限。

server_name 应该是唯一的参考服务器。 服务器定义在服务器范围内是全局的,无法将服务器定义限定为特定数据库。 server_name 最大长度为64个字符(超过64个字符的名称被静默截断),并且不区分大小写。 您可以将名称指定为带引号的字符串。

wrapper_name 是一个标识符,可以用单引号引用。

对于每个, option 您必须指定字符文字或数字文字。 字符文字是UTF-8,最大长度为64个字符,默认为空(空)字符串。 字符串文字被静默截断为64个字符。 数字文字必须是0到9999之间的数字,默认值为0。

注意

OWNER 选项当前未应用,并且对创建的服务器连接的所有权或操作没有影响。

CREATE SERVER 语句在 mysql.servers 表中 创建一个条目, 以后可以 CREATE TABLE 在创建 FEDERATED 语句 一起使用 您指定的选项将用于填充表中的 mysql.servers 列。 该表包括 Server_name Host Db Username Password Port Socket

例如:

创建服务器
FOREIGN DATA WRAPPER mysql
选项(用户'远程',主机'198.51.100.106',数据库'测试');

请务必指定与服务器建立连接所需的所有选项。 用户名,主机名和数据库名是必需的。 也可能需要其他选项,例如密码。

创建与 FEDERATED 的连接时,可以使用存储在表中的数据

CREATE TABLE t(s1 INT)ENGINE = FEDERATED CONNECTION ='s';

有关更多信息,请参见 第16.8节“FEDERATED存储引擎”

CREATE SERVER 导致隐式提交。 请参见 第13.3.3节“导致隐式提交的语句”

CREATE SERVER 无论正在使用的日志记录格式如何,都不会写入二进制日志。

13.1.19创建空间参考系统语法

创建或替换空间参考系统
     ......srid srs_attribute

创建空间参考系统
    [IF NOT EXISTS]
    srid srs_attribute ...

srs_attribute:{
    名称 'srs_name '
  | 定义'definition '
  | 组织org_name'IDENTIFIED BY org_id
  | 说明'description '
}

sridorg_id32-bit unsigned integer

此语句创建 空间参照系 (SRS)定义并将其存储在数据字典中。 可以使用该 INFORMATION_SCHEMA ST_SPATIAL_REFERENCE_SYSTEMS 检查定义 此声明需要该 SUPER 权限。

如果既未 指定 OR REPLACE IF NOT EXISTS 指定,则如果已存在具有SRID值的SRS定义,则会发生错误。

使用 CREATE OR REPLACE 语法,将替换具有相同SRID值的任何现有SRS定义,除非现有表中的某些列使用SRID值。 在这种情况下,会发生错误。 例如:

MySQL的> CREATE OR REPLACE SPATIAL REFERENCE SYSTEM 4326 ...;
ERROR 3716(SR005):无法修改SRID 4326。有
至少有一列取决于它。

要标识哪个或哪些列使用SRID,请使用以下查询:

SELECT * FROM INFORMATION_SCHEMA.ST_GEOMETRY_COLUMNS WHERE SRS_ID = 4326;

使用 CREATE ... IF NOT EXISTS 语法,任何具有相同SRID值的现有SRS定义都会导致忽略新定义并发出警告。

SRID值必须在32位无符号整数的范围内,具有以下限制:

  • SRID 0是有效的SRID,但不能与之一起使用 CREATE SPATIAL REFERENCE SYSTEM

  • 如果该值在保留的SRID范围内,则会发出警告。 保留范围为[0,32767](由EPSG保留),[60,000,000,69,999,999](由EPSG保留)和[2,000,000,000,2,147,483,647](由MySQL保留)。 EPSG代表 欧洲石油调查组

  • 用户不应在保留范围内创建具有SRID的SRS。 这样做可能会导致SRID与MySQL分发的未来SRS定义冲突,从而导致新系统提供的SRS未安装用于MySQL升级或用户定义的SRS被覆盖。

语句的属性必须满足以下条件:

  • 属性可以按任何顺序给出,但不能多次给出属性。

  • NAME DEFINITION 属性是强制性的。

  • NAME srs_name 属性值必须是唯一的。 ORGANIZATION org_name org_id 属性值 的组合 必须是唯一的。

  • NAME srs_name 属性值和 ORGANIZATION org_name 属性值不能为空或开始或空白结束。

  • 属性规范中的字符串值不能包含控制字符,包括换行符。

  • 下表显示了字符串属性值的最大长度。

    表13.6创建空间参考系统属性长度

    属性 最大长度(字符)
    NAME 80
    DEFINITION 4096
    ORGANIZATION 256
    DESCRIPTION 2048

这是一个示例 CREATE SPATIAL REFERENCE SYSTEM 声明。 为了 DEFINITION 便于阅读, 值在多行中重新格式化。 (对于合法的陈述,实际上必须在一行上给出该值。)

创建空间参考系统4120
姓名'希腊'
组织'EPSG'由4120识别
定义
  'GEOGCS [“希腊语”,DATUM [“希腊语”,SPHEROID [“Bessel 1841”,
  6377397.155,299.1528128,AUTHORITY [ “EPSG”, “7004”]],
  AUTHORITY [ “EPSG”, “6120”]],PRIMEM [ “格林威治”,0,
  AUTHORITY [ “EPSG”, “8901”]],单位[ “度”,0.017453292519943278,
  AUTHORITY [ “EPSG”, “9122”]],AXIS [ “纬度”,NORTH],AXIS [ “经度”,EAST]
  AUTHORITY [ “EPSG”, “4120”]]“;

SRS定义的语法基于 OpenGIS Implementation Specification:Coordinate Transformation Services ,Revision 1.00,OGC 01-009,2001年1月12日,第7.2节中 定义的语法 该规范可从 http://www.opengeospatial.org/standards/ct获得

MySQL将这些更改合并到规范中:

  • 仅实施 <horz cs> 生产规则(即,地理和预计的SRS)。

  • 有一个可选的非标准 <authority> 条款 <parameter> 这使得可以通过权限而不是名称来识别投影参数。

  • 规范没有 AXIS GEOGCS 空间参考系统定义中 强制 使用 子句 但是,如果没有 AXIS 子句,MySQL无法确定定义是否具有纬度 - 经度顺序或经度 - 纬度顺序的轴。 MySQL强制执行非标准要求,即每个 GEOGCS 定义必须包含两个 AXIS 子句。 一个必须是, NORTH SOUTH 另一个 EAST WEST AXIS 子句顺序决定的定义是否在纬度-经度顺序或经纬度顺序轴。

  • SRS定义可能不包含换行符。

如果SRS定义指定了投影的权限代码(建议使用),则如果定义缺少必需参数,则会发生错误。 在这种情况下,错误消息表明问题是什么。 MySQL支持的投影方法和强制参数如 表13.7“支持的空间参考系统投影方法” 表13.8“空间参考系统投影参数”所示

有关编写SRS定义为MySQL的更多信息,请参见 在MySQL 8.0地理空间参考系统 投影空间参照系在MySQL 8.0

下表显示了MySQL支持的投影方法。 MySQL允许未知的投影方法,但无法检查强制参数的定义,也无法将空间数据转换为未知投影或从未知投影转换空间数据。 有关每个投影如何工作的详细说明,包括公式,请参阅 EPSG指导说明7-2

表13.7支持的空间参考系统投影方法

EPSG代码 投影名称 强制参数(EPSG代码)
1024 流行的可视化伪墨卡托 8801,8802,8806,8807
1027 Lambert Azimuthal等面积(球面) 8801,8802,8806,8807
1028 等距圆柱形 8823,8802,8806,8807
1029 等距圆柱(球面) 8823,8802,8806,8807
1041 Krovak(朝北) 8811,8833,1036,8818,8819,8806,8807
1042 Krovak修改 8811,8833,1036,8818,8819,8806,8807,8617,8618,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035
1043 Krovak改装(朝北) 8811,8833,1036,8818,8819,8806,8807,8617,8618,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035
1051 Lambert Conic Conformal(密歇根州2SP) 8821,8822,8823,8824,8826,8827,1038
1052 哥伦比亚城市 8801,8802,8806,8807,1039
9801 Lambert Conic Conformal(1SP) 8801,8802,8805,8806,8807
9802 Lambert Conic Conformal(2SP) 8821,8822,8823,8824,8826,8827
9803 Lambert Conic Conformal(2SP比利时) 8821,8822,8823,8824,8826,8827
9804 墨卡托(变种A) 8801,8802,8805,8806,8807
9805 墨卡托(变种B) 8823,8802,8806,8807
9806 卡西尼 - 雇佣兵 8801,8802,8806,8807
9807 横向墨卡托 8801,8802,8805,8806,8807
9808 横向墨卡托(南方定向) 8801,8802,8805,8806,8807
9809 倾斜立体 8801,8802,8805,8806,8807
9810 极地立体(变体A) 8801,8802,8805,8806,8807
9811 新西兰地图网格 8801,8802,8806,8807
9812 Hotine Oblique Mercator(变体A) 8811,8812,8813,8814,8815,8806,8807
9813 Laborde Oblique Mercator 8811,8812,8813,8815,8806,8807
9815 Hotine Oblique Mercator(变体B) 8811,8812,8813,8814,8815,8816,8817
9816 突尼斯矿业网 8821,8822,8826,8827
9817 Lambert Conic近共形 8801,8802,8805,8806,8807
9818 美国的Polyconic 8801,8802,8806,8807
9819 Krovak 8811,8833,1036,8818,8819,8806,8807
9820 Lambert Azimuthal平等区域 8801,8802,8806,8807
9822 Albers Equal Area 8821,8822,8823,8824,8826,8827
9824 横向墨卡托分区网格系统 8801,8830,8831,8805,8806,8807
9826 Lambert Conic Conformal(西方定向) 8801,8802,8805,8806,8807
9828 Bonne(南方定位) 8801,8802,8806,8807
9829 极地立体图(变体B) 8832,8833,8806,8807
9830 极地立体(变体C) 8832,8833,8826,8827
9831 关岛投射 8801,8802,8806,8807
9832 改进的Azimuthal等距离 8801,8802,8806,8807
9833 双曲卡西尼号战士 8801,8802,8806,8807
9834 朗伯圆柱等面积(球面) 8823,8802,8806,8807
9835 朗伯圆柱面积等面积 8823,8802,8806,8807

下表显示了MySQL识别的投影参数。 识别主要由权威代码发生。 如果没有权限代码,MySQL将回退到参数名称上不区分大小写的字符串匹配。 有关每个参数的详细信息,请通过 EPSG Online Registry 中的代码进行查找

表13.8空间参考系统投影参数

EPSG代码 后备名称(由MySQL认可) EPSG名称
1026 C1 C1
1027 C2 C2
1028 C3 C3
1029 C4 C4
1030 C5 C5
1031 C6 C6
1032 C7 C7
1033 C8 C8
1034 C9 C9
1035 C10 C10
1036 方位 锥轴的共同纬度
1038 ellipsoid_scale_factor 椭球比例因子
1039 projection_plane_height_at_origin 投影平面原点高度
8617 evaluation_point_ordinate_1 纵坐标1评价点
8618 evaluation_point_ordinate_2 纵坐标评价点2
8801 latitude_of_origin 纬度自然来源
8802 central_meridian 经度来源于自然
8805 比例因子 天然来源的比例因子
8806 false_easting 虚假的东方
8807 false_northing 假北上
8811 latitude_of_center 投影中心的纬度
8812 longitude_of_center 投影中心的经度
8813 方位 初始线的方位角
8814 rectified_grid_angle 从整流到偏斜网格的角度
8815 比例因子 初始线上的比例因子
8816 false_easting 在投影中心东边
8817 false_northing 北投影中心
8818 pseudo_standard_parallel_1 纬度的标准并行
8819 比例因子 伪标准并行的比例因子
8821 latitude_of_origin 虚假来源的纬度
8822 central_meridian 虚假出身的经度
8823 standard_parallel_1,standard_parallel1 第一标准平行纬度
8824 standard_parallel_2,standard_parallel2 纬度为第二标准平行
8826 false_easting 东方是错误的起源
8827 false_northing 北方在虚假的起源
8830 initial_longitude 初始经度
8831 zone_width 区域宽度
8832 standard_parallel 纬度标准平行
8833 longitude_of_center 经度

13.1.20 CREATE TABLE语法

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_namecreate_definition,...)
    [ table_options]
    [ partition_options]

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
    [(create_definition,...)]
    [ table_options]
    [ partition_options]
    [IGNORE | 更换]
    [如] query_expression

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
    {LIKE old_tbl_name| (LIKE old_tbl_name)}

create_definition
  | {INDEX | KEY} [ ] [ ](,...)col_name column_definitionindex_nameindex_typekey_part
      [ index_option] ......
  | {FULLTEXT | SPATIAL} [INDEX | KEY] [ index_name](key_part,...)
      [ index_option] ......
  | [CONSTRAINT [ symbol]] PRIMARY KEY
      [ index_type](key_part,...)
      [ index_option] ......
  | [CONSTRAINT [ symbol]] UNIQUE [INDEX | KEY]
      [ index_name] [ index_type](key_part,...)
      [ index_option] ......
  | [CONSTRAINT [ symbol]]外键
      [ index_name](col_name,...)
       reference_definition
  |check_constraint_definition

column_definitiondata_type[NOT NULL | NULL] [DEFAULT { literal| expr)}]
      [AUTO_INCREMENT] [UNIQUE [KEY]] [[PRIMARY] KEY]
      [评论'string ']
      [收集collation_name]
      [COLUMN_FORMAT {FIXED | DYNAMIC | DEFAULT}]
      [STORAGE {DISK | MEMORY}]
      [ reference_definition]
      [ check_constraint_definition]
  | data_type
      [收集collation_name]
      [GENERATED ALWAYS] AS(expr
      [VIRTUAL | 存储] [NOT NULL | 空值]
      [UNIQUE [KEY]] [[PRIMARY] KEY]
      [评论'string ']
      [reference_definition]
      [ check_constraint_definition]

data_type
    (见第11章,数据类型

key_part:{ col_name[(length)] | expr)} [ASC | DESC]

index_type
    使用{BTREE | HASH}

index_option
    KEY_BLOCK_SIZE [=] value
  | index_type
  | 与PARSER parser_name
  | 评论'string'
  | {VISIBLE | 无形}

check_constraint_definition
    [CONSTRAINT [ symbol]] CHECK(expr)[[NOT] ENFORCED]

reference_definition
    参考文献tbl_namekey_part,...)
      [匹配完整| 匹配部分| 匹配简单]
      [ON DELETE reference_option]
      [ON UPDATE reference_option]

reference_option
    限制| CASCADE | SET NULL | 没有动作| 默认设置

table_optionstable_option[[,] table_option] ......

table_option
    AUTO_INCREMENT [=] value
  | AVG_ROW_LENGTH [=] value
  | [DEFAULT] CHARACTER SET [=]charset_name
  | CHECKSUM [=] {0 | 1}
  | [DEFAULT] COLLATE [=] collation_name
  | 评论[=]' string'
  | COMPRESSION [=] {'ZLIB'|'LZ4'|'NONE'}
  | 连接[=]' connect_string'
  | {DATA | INDEX} DIRECTORY [=]' absolute path to directory'
  | DELAY_KEY_WRITE [=] {0 | 1}
  | ENCRYPTION [=] {'Y'| 'N'}
  | 发动机[=]engine_name
  | INSERT_METHOD [=] {NO | 第一个| 最后}
  | KEY_BLOCK_SIZE [=] value
  | MAX_ROWS [=] value
  | MIN_ROWS [=]value
  | PACK_KEYS [=] {0 | 1 | 默认}
  | 密码[=]' string'
  | ROW_FORMAT [=] {DEFAULT | DYNAMIC | FIXED | COMPRESSED | REDUNDANT | COMPACT}
  | STATS_AUTO_RECALC [=] {DEFAULT | 0 | 1}
  | STATS_PERSISTENT [=] {DEFAULT | 0 | 1}
  | STATS_SAMPLE_PAGES [=] value
  | TABLESPACE tablespace_name[STORAGE {DISK | MEMORY}]
  | UNION [=](tbl_name[,tbl_name] ......)

partition_options
    分区
        {[LINEAR] HASH(expr
        | [LINEAR] KEY [ALGORITHM = {1 | 2}](column_list
        | 范围{(expr)| COLUMNS(column_list)}
        | 列表{(expr)| COLUMNS(column_list)}}
    [PARTITIONS num]
    [SUBPARTITION BY
        {[LINEAR] HASH(expr
        | [LINEAR] KEY [ALGORITHM = {1 | 2}](column_list)}
      [SUBPARTITIONS num]
    ]
    [(partition_definition[,partition_definition] ......)]

partition_definition
    划分 partition_name
        [VALUES
            {不到{(expr| value_list)| MAXVALUE}
            |
            IN(value_list)}]
        [[STORAGE] ENGINE [=] engine_name]
        [评论[=]' string']
        [DATA DIRECTORY [=]' data_dir']
        [INDEX DIRECTORY [=]' index_dir']
        [MAX_ROWS [=] max_number_of_rows]
        [MIN_ROWS [=] min_number_of_rows]
        [TABLESPACE [=] tablespace_name]
        [(subpartition_definition[,subpartition_definition] ......)]

subpartition_definition
    SUBPARTITION logical_name
        [[STORAGE] ENGINE [=] engine_name]
        [评论[=]' string']
        [DATA DIRECTORY [=]' data_dir']
        [INDEX DIRECTORY [=]' index_dir']
        [MAX_ROWS [=] max_number_of_rows]
        [MIN_ROWS [=] min_number_of_rows]
        [TABLESPACE [=] tablespace_name]

query_expression:
    选择......(Some valid select or union statement

CREATE TABLE 创建一个具有给定名称的表。 您必须拥有 CREATE 该表 权限。

默认情况下,使用 InnoDB 存储引擎 在默认数据库中创建表 如果表存在,如果没有默认数据库,或者数据库不存在,则会发生错误。

有关表的物理表示的信息,请参见 第13.1.20.2节“由CREATE TABLE创建的文件”

CREATE TABLE 创建表时,MySQL将存储 原始 语句,包括所有规范和表选项。 有关更多信息,请参见 第13.1.20.1节“CREATE TABLE语句保留”

CREATE TABLE 声明 有几个方面 ,在本节的以下主题中描述:

表名

  • tbl_name

    可以指定表名 db_name.tbl_name 以在特定数据库中创建表。 假设数据库存在,无论是否存在默认数据库,这都有效。 如果使用带引号的标识符,请分别引用数据库和表名。 例如,写 `mydb`.`mytbl` ,不 `mydb.mytbl`

    第9.2节“模式对象名称” 中给出了允许的表名称的规则

  • IF NOT EXISTS

    如果表存在,则防止发生错误。 但是,没有验证现有表的结构与 CREATE TABLE 语句 指示的结构相同

临时表

您可以 TEMPORARY 在创建表时 使用该 关键字。 一个 TEMPORARY 表只在当前会话中可见,而当会话关闭时自动删除。 有关更多信息,请参见 第13.1.20.3节“CREATE TEMPORARY TABLE语法”

表克隆和复制

列数据类型和属性

每个表的硬限制为4096列,但给定表的有效最大值可能更小,并取决于 第C.10.4节“表列计数和行大小限制”中 讨论的因素

  • data_type

    data_type 表示列定义中的数据类型。 有关可用于指定列数据类型的语法的完整说明,以及有关每种类型的属性的信息,请参见 第11章, 数据类型

    • 某些属性不适用于所有数据类型。 AUTO_INCREMENT 仅适用于整数和浮点类型。 在此之前的MySQL 8.0.13, DEFAULT 并不适用于 BLOB TEXT GEOMETRY ,和 JSON 类型。

    • 字符数据类型( CHAR VARCHAR ,的 TEXT 类型, ENUM SET ,和任何同义词)同义词)可以包括 CHARACTER SET 指定的字符的列设置。 CHARSET 是...的同义词 CHARACTER SET 可以使用 COLLATE 属性以及任何其他属性 指定字符集的排序规则 有关详细信息,请参见 第10章, 字符集,排序规则,Unicode 例:

      CREATE TABLE t(c CHAR(20)CHARACTER SET utf8 COLLATE utf8_bin);
      

      MySQL 8.0以字符形式解释字符列定义中的长度规范。 长度为 BINARY VARBINARY 以字节 单位。

    • CHAR VARCHAR BINARY ,和 VARBINARY 列,索引可以创建仅使用列值的前导部分,使用 语法来指定一个索引前缀长度。 列也可以编入索引,但 必须 给出 前缀长度 对于非二进制字符串类型,前缀长度以字符给出,对于二进制字符串类型,以字节为单位给出。 即,索引项由所述第一的 每个列的值的字符 col_name(length) BLOB TEXT length CHAR VARCHAR TEXT 列,并且所述第一 length 对每个列的值的字节 BINARY VARBINARY BLOB 列。 仅索引像这样的列值的前缀可以使索引文件更小。 有关索引前缀的其他信息,请参见 第13.1.15节“CREATE INDEX语法”

      只有 InnoDB MyISAM 存储引擎支持索引 BLOB TEXT 列。 例如:

      CREATE TABLE test(blob_col BLOB,INDEX(blob_col(10)));
      

      如果指定的索引前缀超过最大列数据类型大小, CREATE TABLE 则按如下方式处理索引:

      • 对于非唯一索引,要么发生错误(如果启用了严格的SQL模式),要么索引长度减少到最大列数据类型大小,并产生警告(如果未启用严格SQL模式)。

      • 对于唯一索引,无论SQL模式如何都会发生错误,因为减少索引长度可能会导致插入不符合指定唯一性要求的非唯一条目。

    • JSON 列无法编入索引。 您可以通过在生成的列上创建索引来解决此限制,该 JSON 从列中提取标量值 有关 详细示例, 请参阅 索引生成的列以提供JSON列索引

  • NOT NULL | NULL

    如果既未 指定 NULL NOT NULL 指定,则将列视为 NULL 已指定。

    在MySQL 8.0中,只有 InnoDB MyISAM 以及 MEMORY 在可以有列存储引擎支持索引 NULL 值。 在其他情况下,您必须将索引列声明为 NOT NULL 错误结果。

  • DEFAULT

    指定列的默认值。 有关默认值处理的更多信息,包括列定义不包含显式 DEFAULT 值的情况,请参见 第11.7节“数据类型默认值”

    如果 启用 NO_ZERO_DATE NO_ZERO_IN_DATE SQL模式并且根据该模式的日期值默认值不正确, CREATE TABLE 则在未启用严格SQL模式时生成警告,如果启用了严格模式则生成错误。 例如, NO_ZERO_IN_DATE 启用后, c1 DATE DEFAULT '2010-00-00' 会生成警告。

  • AUTO_INCREMENT

    整数或浮点列可以具有附加属性 AUTO_INCREMENT 当您插入值 NULL (推荐)或 0 索引 AUTO_INCREMENT 列时,该列将设置为下一个序列值。 通常,这是 value+1 ,这里 value 是目前在表中的列的最大值。 AUTO_INCREMENT 序列开头 1

    AUTO_INCREMENT 在插入行后 检索 值,请使用 LAST_INSERT_ID() SQL函数或 mysql_insert_id() C API函数。 请参见 第12.15节“信息函数” 第28.7.7.38节“mysql_insert_id()”

    如果 NO_AUTO_VALUE_ON_ZERO 启用 SQL模式,则可以 0 AUTO_INCREMENT 列中 存储 0 而不生成新的序列值。 请参见 第5.1.11节“服务器SQL模式”

    AUTO_INCREMENT 每个表 只能有一 列,必须编制索引,并且不能有 DEFAULT 值。 AUTO_INCREMENT 列正常工作,只有当它仅包含正值。 插入负数被视为插入一个非常大的正数。 这样做是为了避免数字 从正到负 包裹 时的精度问题, 并确保您不会意外地获得 AUTO_INCREMENT 包含 0

    对于 MyISAM 表,您可以 AUTO_INCREMENT 在多列键中 指定 辅助列。 请参见 第3.6.9节“使用AUTO_INCREMENT”

    要使MySQL与某些ODBC应用程序兼容,您可以 AUTO_INCREMENT 使用以下查询 找到 最后插入行 值:

    SELECT * FROM tbl_nameWHERE为auto_colNULL
    

    此方法要求 sql_auto_is_null 变量未设置为0.请参见 第5.1.8节“服务器系统变量”

    有关信息 InnoDB ,并 AUTO_INCREMENT 请参见 第15.6.1.4,“AUTO_INCREMENT InnoDB的处理” 有关 AUTO_INCREMENT 和MySQL Replication的信息,请参见 第17.4.1.1节“Replication和AUTO_INCREMENT”

  • COMMENT

    可以使用 COMMENT 选项 指定列的注释 ,最多1024个字符。 注释由 SHOW CREATE TABLE SHOW FULL COLUMNS 语句 显示

  • COLUMN_FORMAT

    在NDB簇,它也可以指定的各个列的数据存储格式 NDB 使用表 COLUMN_FORMAT 允许列格式 FIXED DYNAMIC 以及 DEFAULT FIXED 用于指定固定宽度存储, DYNAMIC 允许 DEFAULT 列为 可变宽度, 并使列使用由列的数据类型确定的固定宽度或可变宽度存储(可能由 ROW_FORMAT 说明符 覆盖 )。

    对于 NDB 表, COLUMN_FORMAT is 的默认值 FIXED

    在NDB Cluster中,定义的列的最大可能偏移量为 COLUMN_FORMAT=FIXED 8188字节。 有关更多信息和可能的解决方法,请参见 第22.1.7.5节“与NDB集群中的数据库对象关联的限制”

    COLUMN_FORMAT 目前对使用除存储引擎之外的表的列没有影响 NDB MySQL 8.0默默地忽略 COLUMN_FORMAT

  • STORAGE

    对于 NDB 表,可以使用 STORAGE 子句 指定列是存储在磁盘上还是存储在内存中 STORAGE DISK 导致列存储在磁盘上,并 STORAGE MEMORY 导致使用内存存储。 使用的 CREATE TABLE 声明必须包括一个 TABLESPACE 条款:

    mysql> CREATE TABLE t1 (
        - >      c1 INT STORAGE DISK,
        - >      c2 INT STORAGE MEMORY
        - > ERROR 1005(HY000):无法创建表'c.t1'(错误号:140)) ENGINE NDB;
    
    
    mysql> CREATE TABLE t1 (
        - >      c1 INT STORAGE DISK,
        - >      c2 INT STORAGE MEMORY
        - >) TABLESPACE ts_1 ENGINE NDB;
    查询OK,0行受影响(1.06秒)
    

    对于 NDB 表, STORAGE DEFAULT 相当于 STORAGE MEMORY

    STORAGE 子句对使用除以外的存储引擎的表没有影响 NDB STORAGE 仅在 与NDB Cluster一起提供 mysqld 的构建中支持 关键字 ; 在任何其他版本的MySQL中都无法识别,任何尝试使用该 STORAGE 关键字都会导致语法错误。

  • GENERATED ALWAYS

    用于指定生成的列表达式。 有关 生成的列的 信息 ,请参见 第13.1.20.9节“创建表和生成的列”

    存储生成的列 可以编制索引。 InnoDB 支持 虚拟生成列 上的二级索引 请参见 第13.1.20.10节“二级索引和生成的列”

索引,外键和CHECK约束

有几个关键字适用于索引,外键和 CHECK 约束的创建。 除了以下描述之外,还有一般背景知识,请参见 第13.1.15节“CREATE INDEX语法” 第13.1.20.6节“使用FOREIGN KEY约束” 第13.1.20.7节“检查约束”

  • CONSTRAINT symbol

    可以给出 子句来命名约束。 如果未给出该子句,或者 关键字 后面不包含 a ,则MySQL会自动生成约束名称,但下面会有例外情况。 对于 每个约束类型, 值(如果使用)对于每个模式(数据库)必须是唯一的。 重复会 导致错误。 CONSTRAINT symbol symbol CONSTRAINT symbol symbol

    注意

    如果 在外键定义中没有给出 子句,或者 关键字 后面不包含 a ,则MySQL使用外键索引名称直到MySQL 8.0.15,并在此后自动生成约束名称。 CONSTRAINT symbol symbol CONSTRAINT

    SQL标准指定所有类型的约束(主键,唯一索引,外键,检查)属于同一名称空间。 在MySQL中,每个约束类型都有自己的每个模式的命名空间。 因此,每种类型的约束的名称对于每个模式必须是唯一的。

  • PRIMARY KEY

    唯一索引,其中必须将所有键列定义为 NOT NULL 如果没有明确 NOT NULL 声明它们,MySQL就会隐式声明(并且默默地)。 一张桌子只能有一张 PRIMARY KEY a的名称 PRIMARY KEY 始终为 PRIMARY ,因此不能用作任何其他类型索引的名称。

    如果你没有a PRIMARY KEY 和应用程序要求 PRIMARY KEY 你的表,MySQL将返回第一个 UNIQUE 没有 NULL 列的 索引 PRIMARY KEY

    InnoDB 表中,保留 PRIMARY KEY short以最小化二级索引的存储开销。 每个辅助索引条目都包含相应行的主键列的副本。 (参见 第15.6.2.1节“聚集和二级索引” 。)

    在创建的表中, PRIMARY KEY 首先放置 a ,然后放置所有 UNIQUE 索引,然后 放置 非唯一索引。 这有助于MySQL优化器确定要使用哪个索引的优先级,并且还可以更快地检测重复的 UNIQUE 密钥。

    A PRIMARY KEY 可以是多列索引。 但是,您无法使用 PRIMARY KEY 列规范中 键属性 创建多列索引 这样做只会将单列标记为主列。 您必须使用单独的 条款。 PRIMARY KEY(key_part, ...)

    如果表具有 由具有整数类型的单个列组成的索引 PRIMARY KEY UNIQUE NOT NULL 索引,则可以用于 _rowid 引用 SELECT 语句中 的索引列 ,如 唯一索引中所述

    在MySQL中,a的名称 PRIMARY KEY PRIMARY 对于其他指标,如果不指定一个名称,该指数被分配相同的名称作为第一个索引列,有一个可选的后缀( _2 _3 ... ),以使其独特。 您可以使用查看表的索引名称 请参见 第13.7.6.22节“SHOW INDEX语法” SHOW INDEX FROM tbl_name

  • KEY | INDEX

    KEY 通常是...的同义词 INDEX 键属性 PRIMARY KEY 也可以 KEY 在列定义中 指定 时指定。 这是为了与其他数据库系统兼容而实现的。

  • UNIQUE

    一个 UNIQUE 索引创建的约束,使得该指数的所有值必须是不同的。 如果您尝试添加具有与现有行匹配的键值的新行,则会发生错误。 对于所有引擎, UNIQUE 索引允许 NULL 包含的列的 多个 NULL 如果为 UNIQUE 索引中的列 指定前缀值 ,则列值必须在前缀长度内是唯一的。

    如果表具有 由具有整数类型的单个列组成的索引 PRIMARY KEY UNIQUE NOT NULL 索引,则可以用于 _rowid 引用 SELECT 语句中 的索引列 ,如 唯一索引中所述

  • FULLTEXT

    一个 FULLTEXT 指标是用于全文搜索索引的一种特殊类型。 只有 InnoDB MyISAM 存储引擎支持 FULLTEXT 索引。 他们只能从创建 CHAR VARCHAR TEXT 列。 索引总是发生在整个列上; 不支持列前缀索引,如果指定,则忽略任何前缀长度。 有关 操作的详细信息, 请参见 第12.9节“全文搜索功能” WITH PARSER 子句可以被指定为一个 index_option 如果全文索引和搜索操作需要特殊处理,则将解析器插件与索引相关联的值。 该子句仅对 FULLTEXT 索引 有效 InnoDB MyISAM 支持全文解析器插件。 有关详细信息,请参阅 全文分析器插件 第29.2.4.4节“编写全文分析器插件”

  • SPATIAL

    您可以 SPATIAL 在空间数据类型上 创建 索引。 仅支持 InnoDB MyISAM 表的 空间类型 ,并且必须将索引列声明为 NOT NULL 请参见 第11.5节“空间数据类型”

  • FOREIGN KEY

    MySQL支持外键,它允许您跨表交叉引用相关数据,以及外键约束,这有助于保持这种展开数据的一致性。 有关定义和选项信息,请参阅 reference_definition reference_option

    使用 InnoDB 存储引擎的 分区表 不支持外键。 有关 更多信息 请参见 第23.6节“分区的限制和限制”

  • CHECK

    CHECK 子句允许创建要检查表行中数据值的约束。 请参见 第13.1.20.7节“检查约束”

  • key_part

    • key_part 规格可以与结束 ASC DESC 以指定的索引值是否被存储在升序或降序。 如果未给出订单说明符,则默认值为升序。

    • length 属性 定义的前缀 最长可达767个字节 InnoDB 使用 REDUNDANT COMPACT 行格式的 表, 对于 InnoDB 使用 DYNAMIC COMPRESSED 行格式的 表, 前缀长度限制为3072字节 对于 MyISAM 表,前缀长度限制为1000个字节。

      前缀 限制 以字节为单位。 然而,前缀 长度 为索引规范 CREATE TABLE ALTER TABLE CREATE INDEX 语句解释为非二进制字符串类型(字符数 CHAR VARCHAR TEXT )和字节数为二进制串类型( BINARY VARBINARY BLOB )。 在为使用多字节字符集的非二进制字符串列指定前缀长度时,请考虑这一点。

  • index_type

    某些存储引擎允许您在创建索引时指定索引类型。 index_type 说明符 的语法 USING type_name

    例:

    CREATE TABLE查找
      (id INT,索引使用BTREE(id))
      ENGINE = MEMORY;
    

    首选位置 USING 位于索引列列表之后。 它可以在列列表之前给出,但不支持在该位置使用该选项,并且将在以后的MySQL版本中删除。

  • index_option

    index_option values指定索引的其他选项。

    • KEY_BLOCK_SIZE

      对于 MyISAM 表, KEY_BLOCK_SIZE 可以选择指定用于索引键块的大小(以字节为单位)。 该值被视为提示; 如有必要,可以使用不同的尺寸。 KEY_BLOCK_SIZE 为单个索引定义指定 值将覆盖表级 KEY_BLOCK_SIZE 值。

      有关表级 KEY_BLOCK_SIZE 属性的信息,请参阅 表选项

    • WITH PARSER

      WITH PARSER 选项只能与 FULLTEXT 索引 一起使用 如果全文索引和搜索操作需要特殊处理,它会将解析器插件与索引相关联。 InnoDB MyISAM 支持全文解析器插件。 如果您的 MyISAM 表具有关联的全文解析器插件,则可以将表转换为 InnoDB 使用 ALTER TABLE

    • COMMENT

      在MySQL 8.0中,索引定义可以包含最多1024个字符的可选注释。

      您可以 InnoDB MERGE_THRESHOLD 使用该 index_option COMMENT 子句 设置 单个索引 请参见 第15.8.11节“配置索引页的合并阈值”

    有关允许 index_option 值的 更多信息 ,请参见 第13.1.15节“CREATE INDEX语法” 有关索引的更多信息,请参见 第8.3.1节“MySQL如何使用索引”

  • reference_definition

    有关 reference_definition 语法详细信息和示例,请参见 第13.1.20.6节“使用FOREIGN KEY约束” 有关外键的特定信息 InnoDB ,请参见 第15.6.1.5节“InnoDB和FOREIGN KEY约束”

    InnoDB NDB 表支持检查外键约束。 必须始终明确命名引用表的列。 无论 ON DELETE ON UPDATE 外键的行动的支持。 有关更多详细信息和示例,请参见 第13.1.20.6节“使用FOREIGN KEY约束” 有关外键的特定信息 InnoDB ,请参见 第15.6.1.5节“InnoDB和FOREIGN KEY约束”

    对于其它存储引擎,MySQL服务器解析,而忽略 FOREIGN KEY REFERENCES 语法的 CREATE TABLE 语句。 请参见 第1.8.2.3节“外键差异”

    重要

    对于熟悉ANSI / ISO SQL标准的用户,请注意,没有存储引擎,包括 InnoDB ,识别或强制执行 MATCH 参照完整性约束定义中使用 子句。 使用explicit MATCH 子句不会产生指定的效果,也会 忽略 cause ON DELETE ON UPDATE 子句。 出于这些原因, MATCH 应该避免 指定

    MATCH SQL标准中 子句控制 NULL 在与主键进行比较时如何处理复合(多列)外键中的值。 InnoDB 本质上实现了定义的语义 MATCH SIMPLE ,允许外键全部或部分 NULL 在这种情况下,允许插入包含此类外键的(子表)行,并且与引用的(父)表中的任何行都不匹配。 可以使用触发器实现其他语义。

    此外,MySQL要求为引用的列编制索引以提高性能。 但是, InnoDB 不强制要求声明引用的列 UNIQUE NOT NULL 对包含 NULL 值的 非唯一键或键的外键引用的处理 没有为诸如 UPDATE 或之类的 操作定义 DELETE CASCADE 建议您使用只引用 UNIQUE (或 PRIMARY )和的 键的外键 NOT NULL

    MySQL解析但忽略了 内联 REFERENCES 规范 (在SQL标准中定义),其中引用被定义为列规范的一部分。 MySQL REFERENCES 仅在指定为单独 FOREIGN KEY 规范的 一部分时才 接受 子句

  • reference_option

    有关信息 RESTRICT CASCADE SET NULL NO ACTION ,和 SET DEFAULT 选项,请参阅 第13.1.20.6,“使用外键约束”

表格选项

表选项用于优化表的行为。 在大多数情况下,您不必指定其中任何一个。 除非另有说明,否则这些选项适用于所有存储引擎 可以接受并记住不适用于给定存储引擎的选项作为表定义的一部分。 如果您稍后使用 ALTER TABLE 转换表以使用其他存储引擎, 则此类选项适用

  • ENGINE

    使用下表中显示的名称之一指定表的存储引擎。 引擎名称可以不加引号或引用。 引用的名称 'DEFAULT' 被识别但被忽略。

    存储引擎 描述
    InnoDB 具有行锁定和外键的事务安全表。 新表的默认存储引擎。 如果你有MySQL经验但是很新的话 请参见 第15章, InnoDB存储引擎 ,特别是 第15.1节“InnoDB简介” InnoDB
    MyISAM 二进制便携式存储引擎,主要用于只读或大部分读取工作负载。 请参见 第16.2节“MyISAM存储引擎”
    MEMORY 此存储引擎的数据仅存储在内存中。 请参见 第16.3节“MEMORY存储引擎”
    CSV 以逗号分隔值格式存储行的表。 请参见 第16.4节“CSV存储引擎”
    ARCHIVE 归档存储引擎。 请参见 第16.5节“ARCHIVE存储引擎”
    EXAMPLE 一个示例引擎。 请参见 第16.9节“示例存储引擎”
    FEDERATED 访问远程表的存储引擎。 请参见 第16.8节“FEDERATED存储引擎”
    HEAP 这是一个同义词 MEMORY
    MERGE MyISAM 用作一个表 的集合 也称为 MRG_MyISAM 请参见 第16.7节“MERGE存储引擎”
    NDB 集群,容错,基于内存的表,支持事务和外键。 也称为 NDBCLUSTER 请参见 第22章, MySQL NDB Cluster 8.0

    默认情况下,如果指定的存储引擎不可用,则该语句将失败并显示错误。 您可以通过 NO_ENGINE_SUBSTITUTION 从服务器SQL模式中 删除来覆盖此行为 (请参见 第5.1.11节“服务器SQL模式” ),以便MySQL允许使用默认存储引擎替换指定的引擎。 通常在这种情况下,这是 系统变量 InnoDB 的默认值 default_storage_engine NO_ENGINE_SUBSTITUTION 被禁用,如果存储引擎规格不兑现出现警告。

  • AUTO_INCREMENT

    AUTO_INCREMENT 的初始 值。 在MySQL 8.0,这个工程的 MyISAM MEMORY InnoDB ,和 ARCHIVE 表格。 要为不支持 AUTO_INCREMENT 表选项的 引擎设置第一个自动增量值,请 在创建表后 插入 一个值小于所需值 虚拟 行,然后删除虚拟行。

    对于支持 语句中 AUTO_INCREMENT 表选项的 引擎 CREATE TABLE ,您还可以使用 重置 值。 该值不能设置为低于列中当前的最大值。 ALTER TABLE tbl_name AUTO_INCREMENT = N AUTO_INCREMENT

  • AVG_ROW_LENGTH

    表格的平均行长度的近似值。 您只需为具有可变大小行的大型表设置此项。

    当您创建 MyISAM 表时,MySQL使用 MAX_ROWS AVG_ROW_LENGTH 选项 的乘积 来确定结果表的大小。 如果未指定任一选项,则 MyISAM 默认情况下数据和索引文件 的最大大小为 256 TB。 (如果您的操作系统不支持较大的文件,则表大小受文件大小限制的限制。)如果您想要保持指针大小以使索引更小更快而且您不需要大文件,那么可以通过设置 myisam_data_pointer_size 系统变量 来减少默认指针大小 (看到 第5.1.8节“服务器系统变量” 。)如果您希望所有表都能够超过默认限制并且愿意让您的表稍微慢一些并且大于必要的值,则可以通过设置此变量来增加默认指针大小。 将值设置为7允许表格大小高达65,536TB。

  • [DEFAULT] CHARACTER SET

    指定表的默认字符集。 CHARSET 是...的同义词 CHARACTER SET 如果字符集名称是 DEFAULT ,则使用数据库字符集。

  • CHECKSUM

    如果希望MySQL为所有行维护实时校验和(即,当表更改时MySQL会自动更新的校验和),请将此值设置为1。 这使得表更新速度稍慢,但也可以更容易地找到损坏的表。 CHECKSUM TABLE 声明报告了校验和。 MyISAM 仅限。)

  • [DEFAULT] COLLATE

    指定表的默认排序规则。

  • COMMENT

    该表的注释,最多2048个字符。

    您可以 InnoDB MERGE_THRESHOLD 使用该 table_option COMMENT 子句 设置 请参见 第15.8.11节“配置索引页的合并阈值”

    设置NDB_TABLE选项。  在该表注释 CREATE TABLE 创建一个 NDB 表或 ALTER TABLE 这会改变一个也可以用于指定一到四个声明 NDB_TABLE 选项 NOLOGGING READ_BACKUP PARTITION_BALANCE ,或 FULLY_REPLICATED 为一组名称-值对,用逗号隔开如果需要的话,紧跟着 NDB_TABLE= 以引用的注释文本开头的 字符串 此处显示了使用此语法的示例语句(强调文本):

    CREATE TABLE t1(
        c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
        c2 VARCHAR(100),
        c3 VARCHAR(100))
    ENGINE = NDB
    COMMENT =“NDB_TABLE = READ_BACKUP = 0,PARTITION_BALANCE = FOR_RP_BY_NODE” ;
    

    引用的字符串中不允许使用空格。 该字符串不区分大小写。

    评论显示为输出的一部分 SHOW CREATE TABLE 注释的文本也可以作为MySQL Information Schema TABLES 的TABLE_COMMENT列

    表的 ALTER TABLE 语句 也支持此注释语法 NDB 请记住,使用的表注释 ALTER TABLE 替换了表可能具有的任何现有注释。

    MERGE_THRESHOLD 表格不支持在表注释中 设置 选项 NDB (忽略它)。

    有关完整的语法信息和示例,请参见 第13.1.20.11节“设置NDB_TABLE选项”

  • COMPRESSION

    用于 InnoDB 表的 页面级压缩的压缩算法 支持的值包括 Zlib LZ4 ,和 None COMPRESSION 属性是通过透明页面压缩功能引入的。 页面压缩仅支持 InnoDB 驻留在 每个表文件表 空间中的表,并且仅在支持稀疏文件和打孔的Linux和Windows平台上可用。 有关更多信息,请参见 第15.9.2节“InnoDB页面压缩”

  • CONNECTION

    FEDERATED 的连接字符串

    注意

    旧版本的MySQL使用 COMMENT 连接字符串 选项。

  • DATA DIRECTORY INDEX DIRECTORY

    对于 InnoDB ,该 子句允许在数据目录之外创建每个表的文件表空间。 表空间数据文件在指定目录中创建,该子目录位于与模式同名的子目录中。 必须启用 变量才能使用该 子句。 必须指定完整目录路径。 有关更多信息,请参见 第15.6.3.6节“在数据目录外创建表空间” DATA DIRECTORY='directory' innodb_file_per_table DATA DIRECTORY

    创建 MyISAM 表时,可以使用 子句, 子句或两者。 它们分别指定放置 表的数据文件和索引文件的位置。 不同 ,MySQL在创建 带有 选项 时不会创建与数据库名对应的子目录 文件在指定的目录中创建。 DATA DIRECTORY='directory' INDEX DIRECTORY='directory' MyISAM InnoDB MyISAM DATA DIRECTORY INDEX DIRECTORY

    您必须有权 FILE 使用 DATA DIRECTORY INDEX DIRECTORY 表选项。

    重要

    分区表将忽略 表级别 DATA DIRECTORY INDEX DIRECTORY 选项。 (Bug#32091)

    这些选项仅在您不使用该 --skip-symbolic-links 选项时有效。 您的操作系统还必须具有可正常工作的线程安全 realpath() 呼叫。 有关 更多完整信息, 请参见 第8.12.2.2节“在Unix上使用MyISAM表的符号链接”

    如果 MyISAM 创建 表没有 DATA DIRECTORY 选项, .MYD 则在数据库目录中创建 文件。 默认情况下,如果 在这种情况下 MyISAM 找到现有 .MYD 文件,则会覆盖它。 这同样适用于 .MYI 没有 INDEX DIRECTORY 选项 创建的表的文件 要禁止此行为,请使用 --keep_files_on_create 选项 启动服务器 ,在这种情况下, MyISAM 不会覆盖现有文件并返回错误。

    如果 MyISAM 使用 DATA DIRECTORY INDEX DIRECTORY 选项 创建表 并且 找到 现有 .MYD .MYI 文件,则MyISAM始终返回错误。 它不会覆盖指定目录中的文件。

    重要

    您不能使用包含MySQL数据目录的路径名 DATA DIRECTORY INDEX DIRECTORY 这包括分区表和单个表分区。 (参见Bug#32167。)

  • DELAY_KEY_WRITE

    如果要在表关闭之前延迟表的密钥更新,请将此值设置为1。 见的描述 delay_key_write 在系统变量 第5.1.8节,“服务器系统变量” MyISAM 仅限。)

  • ENCRYPTION

    ENCRYPTION 子句启用或禁用表的页级数据加密 InnoDB 必须先安装并配置密钥环插件,然后才能启用加密。 在MySQL 8.0.16之前, ENCRYPTION 只能在每个表文件表空间中创建表时指定 子句。 从MySQL 8.0.16开始, ENCRYPTION 在通用表空间中创建表时也可以指定 子句。

    从MySQL 8.0.16开始,如果 ENCRYPTION 未指定子句 ,表将继承默认模式加密 如果 table_encryption_privilege_check 启用了 变量, TABLE_ENCRYPTION_ADMIN 则需要 权限才能创建一个子表 ENCRYPTION 设置与默认架构加密不同 的表 在通用表空间中创建表时,表和表空间加密必须匹配。

    从MySQL 8.0.16开始, 在使用不支持加密的存储引擎时 ,指定 ENCRYPTION 一个值不同于 'N' '' 不允许 子句 此前,该条款被接受。

    有关更多信息,请参见 第15.6.3.9节“InnoDB静态数据加密”

  • INSERT_METHOD

    如果要将数据插入 MERGE 表中,则必须指定 INSERT_METHOD 应插入行的表。 INSERT_METHOD 是一个 MERGE 仅对表 有用的选项 使用值 FIRST LAST 插入第一个或最后一个表,或使用值 NO 来防止插入。 请参见 第16.7节“MERGE存储引擎”

  • KEY_BLOCK_SIZE

    对于 MyISAM 表, KEY_BLOCK_SIZE 可以选择指定用于索引键块的大小(以字节为单位)。 该值被视为提示; 如有必要,可以使用不同的尺寸。 KEY_BLOCK_SIZE 为单个索引定义指定 值将覆盖表级 KEY_BLOCK_SIZE 值。

    对于 InnoDB 表, KEY_BLOCK_SIZE 指定 用于 压缩 页面 大小(以KB为单位) 值被视为提示; 如有必要, 可以使用不同的尺寸 只能小于或等于该 值。 值0表示默认的压缩页面大小,它是该 值的 一半 根据具体情况 ,可能的 值包括 0,1,2,4,8 和16.有关 更多信息 请参见 第15.9.1节“InnoDB表压缩” InnoDB KEY_BLOCK_SIZE InnoDB KEY_BLOCK_SIZE innodb_page_size innodb_page_size innodb_page_size KEY_BLOCK_SIZE

    Oracle建议使 innodb_strict_mode 指定时 KEY_BLOCK_SIZE InnoDB 表。 innodb_strict_mode 被启用,指定一个无效的 KEY_BLOCK_SIZE 值返回一个错误。 如果 innodb_strict_mode 禁用,则无效 KEY_BLOCK_SIZE 值将导致警告,并 KEY_BLOCK_SIZE 忽略 选项。

    Create_options 列响应 SHOW TABLE STATUS 报告 KEY_BLOCK_SIZE 表所使用 的实际 情况 SHOW CREATE TABLE

    InnoDB 只支持 KEY_BLOCK_SIZE 表级。

    KEY_BLOCK_SIZE 不支持32KB和64KB innodb_page_size 值。 InnoDB 表压缩不支持这些页面大小。

    InnoDB KEY_BLOCK_SIZE 在创建临时表时 不支持该 选项。

  • MAX_ROWS

    您计划在表中存储的最大行数。 这不是硬限制,而是存储引擎的提示,表必须能够存储至少这么多行。

    重要

    不推荐 使用 MAX_ROWS with NDB 表来控制表分区的数量。 它在以后的版本中仍然受支持以实现向后兼容性,但在将来的版本中可能会被删除。 请改用PARTITION_BALANCE; 请参阅 设置NDB_TABLE选项

    NDB 存储引擎将这个值作为最大。 如果您打算创建非常大的NDB簇表(含数百万行),你应该使用这个选项,以确保 NDB 分配在用于通过设置存储表的主键的哈希值的哈希表足够数量的指数中的时隙的 ,这里 是您希望插入表中的行数。 MAX_ROWS = 2 * rows rows

    最大值 MAX_ROWS 为4294967295; 较大的值被截断为此限制。

  • MIN_ROWS

    您计划在表中存储的最小行数。 MEMORY 存储引擎使用此选项,因为一个关于内存使用提示。

  • PACK_KEYS

    仅对 MyISAM 表有效。 如果要使用较小的索引,请将此选项设置为1。 这通常会使更新变慢并且读取速度更快。 将该选项设置为0将禁用所有键的打包。 将其设置为 DEFAULT 告诉存储引擎只封装长 CHAR VARCHAR BINARY ,或 VARBINARY 列。

    如果不使用 PACK_KEYS ,则默认为打包字符串,而不是数字。 如果您使用 PACK_KEYS=1 ,也会打包数字。

    在打包二进制数字键时,MySQL使用前缀压缩:

    • 每个密钥都需要一个额外的字节来指示前一个密钥的字节数对于下一个密钥是相同的。

    • 指向该行的指针直接以密钥后的高字节优先顺序存储,以改善压缩。

    这意味着如果在两个连续的行上有许多相等的键,则所有后面的 相同 键通常只占用两个字节(包括指向该行的指针)。 将此与以下键所采用的普通情况 storage_size_for_key + pointer_size (指针大小通常为4)进行比较。 相反,只有当您有许多相同的数字时,才能从前缀压缩中获得显着的好处。 如果所有键完全不同,则每个键使用一个字节,如果键不是可以具有 NULL 的键 (在这种情况下,打包密钥长度存储在用于标记密钥的相同字节中 NULL 。)

  • PASSWORD

    此选项未使用。

  • ROW_FORMAT

    定义存储行的物理格式。

    执行 禁用 严格模式 CREATE TABLE 语句时 ,如果指定了用于表的存储引擎不支持的行格式,则使用该存储引擎的默认行格式创建表。 表的实际行格式在 响应的列中 报告 还会报告表的实际行格式。 Row_format Create_options SHOW TABLE STATUS SHOW CREATE TABLE

    行格式选择因表格使用的存储引擎而异。

    对于 InnoDB 表格:

    • 默认行格式由 innodb_default_row_format ,其默认设置为 DYNAMIC ROW_FORMAT 未定义选项或 使用时使用默认行格式 ROW_FORMAT=DEFAULT

      如果 ROW_FORMAT 未定义 选项,或者 ROW_FORMAT=DEFAULT 使用 了该 选项,则 重建表的操作也会以静默方式将表的行格式更改为默认定义的 innodb_default_row_format 有关更多信息,请参阅 定义表的行格式

    • 为了更有效地 InnoDB 存储数据类型,尤其是 BLOB 类型,请使用 DYNAMIC 有关 行格式 关联的要求, 请参阅 DYNAMIC DYNAMIC 行格式。

    • 要为 InnoDB 启用压缩 ,请指定 ROW_FORMAT=COMPRESSED ROW_FORMAT=COMPRESSED 创建临时表时不支持 选项。 有关 行格式的 要求 请参见 第15.9节“InnoDB表和页面压缩” COMPRESSED

    • 仍然可以通过指定 REDUNDANT 行格式 来请求旧版MySQL中使用的 行格式。

    • 指定非默认 ROW_FORMAT 子句时,请考虑启用 innodb_strict_mode 配置选项。

    • ROW_FORMAT=FIXED 不受支持。 如果 ROW_FORMAT=FIXED innodb_strict_mode 禁用时 指定, InnoDB 发出警告并假定 ROW_FORMAT=DYNAMIC 如果 ROW_FORMAT=FIXED innodb_strict_mode 启用时 指定 (默认值),则 InnoDB 返回错误。

    • 有关 InnoDB 行格式的 其他信息 ,请参见 第15.10节“InnoDB行格式”

    MyISAM 表,该选项值可以是 FIXED DYNAMIC 为静态的或可变长度的行格式。 myisampack 将类型设置为 COMPRESSED 请参见 第16.2.3节“MyISAM表存储格式”

    对于 NDB 表,默认 ROW_FORMAT DYNAMIC

  • STATS_AUTO_RECALC

    指定是否自动重新计算 持续的统计数据 InnoDB 表。 该值 DEFAULT 导致表的持久统计信息设置由 innodb_stats_auto_recalc 配置选项 确定 1 当表中10%的数据发生更改时, 该值 会导致重新计算统计信息。 该值 0 可防止自动重新计算此表; 使用此设置,发出 ANALYZE TABLE 声明以在对表进行实质性更改后重新计算统计信息。 有关持久性统计信息功能的详细信息,请参阅 第15.8.10.1节“配置持久优化器统计信息参数”

  • STATS_PERSISTENT

    指定是否 启用 持久统计信息 InnoDB 该值 DEFAULT 导致表的持久统计信息设置由 innodb_stats_persistent 配置选项 确定 该值 1 启用表的持久统计信息,而值 0 将关闭此功能。 通过 CREATE TABLE or ALTER TABLE 语句 启用持久统计信息后 ,请发出 第15.8.10.1节“配置持久优化器统计信息参数” ANALYZE TABLE 信息后,在将代表性数据加载到表中后 语句来计算统计信息。 有关持久性统计信息功能的详细信息,请参阅

  • STATS_SAMPLE_PAGES

    估计索引列的基数和其他统计信息时要采样的索引页数,例如计算的列 ANALYZE TABLE 有关更多信息,请参见 第15.8.10.1节“配置持久优化器统计信息参数”

  • TABLESPACE

    TABLESPACE 子句可用于在现有通用表空间,每表文件表空间或系统表空间中创建表。

    CREATE TABLE tbl_name... TABLESPACE [=]tablespace_name

    您指定的常规表空间必须在使用该 TABLESPACE 子句 之前存在 有关常规表空间的信息,请参见 第15.6.3.3节“常规表空间”

    tablespace_name 是一个区分大小写的标识符。 它可能是引用或不引用的。 不允许 使用正斜杠字符( / )。 名称以 innodb_ 开头 保留用于特殊用途。

    要在系统表空间中创建表,请指定 innodb_system 为表空间名称。

    CREATE TABLE tbl_name... TABLESPACE [=] innodb_system

    使用时 TABLESPACE [=] innodb_system ,无论 innodb_file_per_table 设置 如何,都可以在系统表空间中放置任何未压缩行格式的表 例如,您可以使用添加表 ROW_FORMAT=DYNAMIC 到系统表空间 TABLESPACE [=] innodb_system

    要在每个表的文件表空间中创建一个表,请指定 innodb_file_per_table 为表空间名称。

    CREATE TABLE tbl_name... TABLESPACE [=] innodb_file_per_table
    注意

    如果 innodb_file_per_table 已启用,则无需指定 TABLESPACE=innodb_file_per_table 创建 InnoDB 每个表 文件表空间。 启用 InnoDB 时,默认情况下,在每个表的表空间中创建表 innodb_file_per_table

    DATA DIRECTORY 条款是允许的, CREATE TABLE ... TABLESPACE=innodb_file_per_table 但不支持与该 TABLESPACE 条款 结合使用

    注意

    自MySQL 8.0.13起,不推荐使用对 支持 TABLESPACE = innodb_file_per_table TABLESPACE = innodb_temporary 子句的 支持, 并将 CREATE TEMPORARY TABLE 在未来的MySQL版本中删除。

    STORAGE 表选项仅采用了与 NDB 表。 STORAGE 确定使用的存储类型(磁盘或内存),可以是 DISK MEMORY

    TABLESPACE ... STORAGE DISK 将表分配给NDB Cluster Disk Data表空间。 必须已使用创建表空间 CREATE TABLESPACE 有关 更多信息 请参见 第22.5.13节“NDB集群磁盘数据表”

    重要

    一个 STORAGE 子句不能被用在 CREATE TABLE 声明中没有 TABLESPACE 从句。

  • UNION

    用于访问一组相同的 MyISAM 表。 这仅适用于 MERGE 表格。 请参见 第16.7节“MERGE存储引擎”

    你必须有 SELECT UPDATE 以及 DELETE 对表的权限您映射到一个 MERGE 表。

    注意

    以前,所有使用的表必须与 MERGE 表本身 在同一个数据库中 此限制不再适用。

表分区

partition_options 可用于控制创建的表的分区 CREATE TABLE

并非所有 partition_options 分区类型都可以使用本节开头 语法中显示的所有选项 有关每种类型的信息,请参阅以下各个类型的列表, 有关MySQL中分区的工作和使用的更完整信息,以及有关表创建和其他相关语句的其他示例, 请参见 第23章 分区 。到MySQL分区。

可以修改,合并,添加到表以及从表中删除分区。 有关完成这些任务的MySQL语句的基本信息,请参见 第13.1.9节“ALTER TABLE语法” 有关更多详细说明和示例,请参见 第23.3节“分区管理”

  • PARTITION BY

    如果使用, partition_options 则以子句开头 PARTITION BY 该子句包含用于确定分区的函数; 该函数返回一个从1到1的整数值 num ,其中 num 是分区数。 (表可能包含的最大用户定义分区数为1024;子区域的数量 - 本节稍后讨论 - 包含在此最大值中。)

    注意

    子句中 expr 使用 的表达式( PARTITION BY 不能引用不在正在创建的表中的任何列; 此类引用是特别不允许的,并导致语句失败并出现错误。 (缺陷#29444)

  • HASH(expr)

    散列一列或多列以创建用于放置和定位行的键。 expr 是使用一个或多个表列的表达式。 这可以是产生单个整数值的任何有效的MySQL表达式(包括MySQL函数)。 例如,这些都是有效的 CREATE TABLE 语句使用 PARTITION BY HASH

    CREATE TABLE t1(col1 INT,col2 CHAR(5))
        HASH分区(col1);
    
    CREATE TABLE t1(col1 INT,col2 CHAR(5),col3 DATETIME)
        哈希分区(年(col3));
    

    您不能使用其中任何一个 VALUES LESS THAN VALUES IN 子句 PARTITION BY HASH

    PARTITION BY HASH 使用余数 expr 除以分区数(即模数)。 有关示例和其他信息,请参见 第23.2.4节“HASH分区”

    LINEAR 关键字需要稍微不同的算法。 在这种情况下,计算存储行的分区的编号作为一个或多个逻辑 AND 操作的结果。 有关线性散列的讨论和示例,请参见 第23.2.4.1节“ 线性散列 分区”

  • KEY(column_list)

    这类似于 HASH ,除了MySQL提供散列函数以保证均匀的数据分布。 column_list 参数是简单的1个或多个表列(最大:16)的列表。 此示例显示了一个按键分区的简单表,包含4个分区:

    CREATE TABLE tk(col1 INT,col2 CHAR(5),col3 DATE)
        PARTITION BY KEY(col3)
        PARTITIONS 4;
    

    对于按键分区的表,可以使用 LINEAR 关键字进行 线性分区 这与分区的表具有相同的效果 HASH 也就是说,使用 & 运算符而不是模 数找到分区号 (有关 详细信息, 请参见 第23.2.4.1节“线性哈希分区” 第23.2.5节“键分区” )。 此示例使用按键的线性分区在5个分区之间分配数据:

    CREATE TABLE tk(col1 INT,col2 CHAR(5),col3 DATE)
        线性键分区(col3)
        PARTITIONS 5;
    

    ALGORITHM={1|2} 选项受支持 [SUB]PARTITION BY [LINEAR] KEY ALGORITHM=1 使服务器使用与MySQL 5.1相同的密钥散列函数; ALGORITHM=2 表示服务器使用默认为 KEY MySQL 5.5及更高版本中的 分区表 实现和使用的密钥散列函数 (使用MySQL 5.5及更高版本中使用的密钥散列函数创建的分区表不能由MySQL 5.1服务器使用。)不指定该选项与使用具有相同的效果 ALGORITHM=2 此选项主要用于升级或降级 [LINEAR] KEY 在MySQL 5.1和更高版本的MySQL版本之间 分区表,或用于创建分区的表时 KEY LINEAR KEY 在MySQL 5.5或更高版本的服务器上,可以在MySQL 5.1服务器上使用。 有关更多信息,请参见 第13.1.9.1节“ALTER TABLE分区操作”

    MySQL 5.7(及更高版本)中的 mysqldump 将此选项写入版本化注释中,如下所示:

    CREATE TABLE t1(INT)
    / *!50100 PARTITION BY KEY * / / *!50611 ALGORITHM = 1 * / / *!50100()
          PARTITIONS 3 * /
    

    这会导致MySQL 5.6.10和更早版本的服务器忽略该选项,否则会导致这些版本中的语法错误。 如果您计划在MySQL 5.7服务器上加载转储,在该服务器中使用分区或子分区的表 KEY 到5.6.11之前的MySQL 5.6服务器,请务必 在继续之前 查阅 MySQL 5.6中的更改 (如果您正在将包含 KEY 由MySQL 5.7实际5.6.11或更高版本服务器组成的分区或子分区表 的转储加载 到MySQL 5.5.30或更早版本的服务器中, 那么此处找到的信息也适用 。)

    同样在MySQL 5.6.11及更高版本中, ALGORITHM=1 必要时在 SHOW CREATE TABLE 使用版本化注释 的输出中 以与 mysqldump 相同的方式显示 即使在创建原始表时指定了此选项,也 ALGORITHM=2 始终从 SHOW CREATE TABLE 输出中 省略

    您不能使用其中任何一个 VALUES LESS THAN VALUES IN 子句 PARTITION BY KEY

  • RANGE(expr)

    在这种情况下, expr 使用一组 VALUES LESS THAN 运算符 显示一系列值 使用范围分区时,必须使用定义至少一个分区 VALUES LESS THAN 您不能使用 VALUES IN 范围分区。

    注意

    对于分区的表 RANGE VALUES LESS THAN 必须与整数文字值或计算结果为单个整数值的表达式一起使用。 在MySQL 8.0中,您可以在使用 PARTITION BY RANGE COLUMNS 本节 定义的表中克服此限制 ,如本节后面所述。

    假设您有一个表,您希望在包含年份值的列上进行分区,根据以下方案。

    分区号码: 年份范围:
    0 1990年及早些时候
    1 1991年至1994年
    2 1995年至1998年
    3 1999年至2002年
    4 2003年至2005年
    2006年及以后

    实现这种分区方案的表可以通过 CREATE TABLE 此处显示 语句 实现

    CREATE TABLE t1(
        year_col INT,
        some_data INT
    按范围划分(year_col)(
        分数p0值低于(1991),
        分区p1值低于(1995),
        分区p2值低于(1999),
        分区p3价值低于(2002年),
        分区p4价值低于(2006年),
        分区p5的值低于MAXVALUE
    );
    

    PARTITION ... VALUES LESS THAN ... 陈述以连续的方式起作用。 VALUES LESS THAN MAXVALUE 用于指定 大于另外指定的最大值的 剩余 值。

    VALUES LESS THAN 子句以类似于 case 部分的 方式顺序工作 switch ... case (如在许多编程语言中找到的那样,如C,Java和PHP)。 也就是说,条款必须以这样的方式排列,即每个连续中指定的上限 VALUES LESS THAN 大于前一个的 上限 ,其中一个引用 MAXVALUE 最后列在列表中。

  • RANGE COLUMNS(column_list)

    此变体 RANGE 有助于使用多列上的范围条件(即具有诸如 WHERE a = 1 AND b < 10 或的 条件 WHERE a = 1 AND b = 10 AND c < 10 对查询进行分区修剪 它允许您通过使用 COLUMNS 子句 中的列列表 和每个 分区定义子句中的 一组列值 来指定多列中的值范围 (在最简单的情况下,此集合由单个列组成。)可以在 和中 引用的最大列数 为16。 PARTITION ... VALUES LESS THAN (value_list) column_list value_list

    column_list 中使用的 COLUMNS 条款可能只包含列的名称; 列表中的每一列必须是以下MySQL数据类型之一:整数类型; 字符串类型; 和时间或日期列类型。 使用列 BLOB TEXT SET ENUM BIT ,或空间数据类型不允许; 也不允许使用浮点数类型的列。 您也可以不在 COLUMNS 子句中 使用函数或算术表达式

    VALUES LESS THAN 分区定义中使用 子句必须为 COLUMNS() 子句 中出现的每个列指定文字值 ; 也就是说,用于每个 VALUES LESS THAN 子句 的值列表 必须包含与 COLUMNS 子句中 列出的列相同数量的值 尝试到在使用更多或更少的值 VALUES LESS THAN 以外还有的条款 COLUMNS 条款会导致失败,错误的语句 在列列表的使用不一致的分区... 您不能使用 NULL 任何出现的值 VALUES LESS THAN 可以使用 MAXVALUE 对于除第一列之外的给定列,不止一次,如下例所示:

    CREATE TABLE rc(
        INT NOT NULL,
        b INT NOT NULL
    按范围栏划分(a,b)(
        分区p0值小于(10,5),
        分区p1值小于(20,10),
        分区p2值小于(50,MAXVALUE),
        分区p3值低于(65,MAXVALUE),
        PARTITION p4值小于(MAXVALUE,MAXVALUE)
    );
    

    VALUES LESS THAN 值列表中 使用的每个值 必须与相应列的类型完全匹配; 没有转换。 例如,您不能将字符串 '1' 用于与使用整数类型的列匹配的值(您必须使用数字 1 ),也不能将数字 1 用于与使用字符串类型的列匹配的值(在此类中)一个案例,你必须使用带引号的字符串:) '1'

    有关更多信息,请参见 第23.2.1节“RANGE分区” 第23.4节“分区修剪”

  • LIST(expr)

    在基于具有一组受限值的可能值(例如州或国家/地区代码)的表列分配分区时,这非常有用。 在这种情况下,可以将属于某个州或国家的所有行分配给单个分区,或者可以为某组州或国家保留分区。 它类似于 RANGE ,除了可以仅 VALUES IN 用于指定每个分区的允许值。

    VALUES IN 与要匹配的值列表一起使用。 例如,您可以创建一个分区方案,如下所示:

    CREATE TABLE client_firms(
        id INT,
        名称VARCHAR(35)
    按名单划分(id)(
        分区r0值((1,5,9,13,17,21),
        分区r1值(2,6,10,14,18,22),
        分区r2值(3,7,11,15,19,23),
        分区r3值(4,8,12,16,20,24)
    );
    

    使用列表分区时,必须使用定义至少一个分区 VALUES IN 您不能使用 VALUES LESS THAN PARTITION BY LIST

    注意

    对于分区的表 LIST ,使用的值列表 VALUES IN 必须仅包含整数值。 在MySQL 8.0中,您可以使用分区来克服此限制 LIST COLUMNS ,本节稍后将对此进行介绍。

  • LIST COLUMNS(column_list)

    此变体 LIST 有助于使用多列上的比较条件(即具有诸如 WHERE a = 5 AND b = 5 或的 条件 WHERE a = 1 AND b = 10 AND c = 5 对查询进行分区修剪 它允许您通过使用 COLUMNS 子句 中的列列表 和每个 分区定义子句中的 一组列值 来指定多列中的 PARTITION ... VALUES IN (value_list)

    管理有关数据类型中使用的列列表中的规则 和使用值列表 是相同的那些在使用的列清单 ,并在使用值列表 分别,只是在 条款, 是不允许的,和你可能会用 LIST COLUMNS(column_list) VALUES IN(value_list) RANGE COLUMNS(column_list) VALUES LESS THAN(value_list) VALUES IN MAXVALUE NULL

    有用于值列表之间的一个重要区别 VALUES IN PARTITION BY LIST COLUMNS ,而不是当它与使用 PARTITION BY LIST 与之一起使用时 PARTITION BY LIST COLUMNS VALUES IN 子句中的 每个元素都 必须是一 列值; 每个集合中的值的数量必须与 COLUMNS 子句中 使用的列数相同 ,并且这些值的数据类型必须与列的数据类型匹配(并以相同的顺序出现)。 在最简单的情况下,该集合由一列组成。 可以 column_list 在构成元素的元素中 使用的最大列数 value_list 为16。

    由以下 CREATE TABLE 语句 定义的表 提供了使用 LIST COLUMNS 分区 的表的示例

    创建表lc(
        一个INT NULL,
        b INT NULL
    列表栏分区(a,b)(
        PARTITION p0 VALUES IN((0,0),(NULL,NULL)),
        分区p1值((0,1),(0,2),(0,3),(1,1),(1,2)),
        分区p2值((1,0),(2,0),(2,1),(3,0),(3,1)),
        ((1,3),(2,2),(2,3),(3,2),(3,3)中的分区p3值)
    );
    
  • PARTITIONS num

    可以选择使用 子句 指定 分区数 ,其中 是分区数。 如果同时使用此子句 任何 子句,则 必须等于使用 子句 声明的任何分区的总数 PARTITIONS num num PARTITION num PARTITION

    注意

    无论是否 PARTITIONS 在创建由 RANGE or 分区的表中 使用 子句 LIST ,您仍必须 PARTITION VALUES 在表定义中 包含至少一个 子句(参见下文)。

  • SUBPARTITION BY

    可以可选地将分区划分为多个子分区。 这可以通过使用optional SUBPARTITION BY 子句 来指示 子分区可以通过 HASH 完成 KEY 这些都可能是 LINEAR 这些工作方式与先前针对等效分区类型所述的方式相同。 (不可能通过 LIST 分区 RANGE 。)

    可以使用 SUBPARTITIONS 关键字后跟整数值 来指示子分区的数量

  • 严格检查使用 PARTITIONS SUBPARTITIONS 子句中使用的值,该值必须符合以下规则:

    • 该值必须是正的非零整数。

    • 不允许前导零。

    • 该值必须是整数文字,并且不能是表达式。 例如, PARTITIONS 0.2E+01 即使 0.2E+01 评估为 ,也不允许 2 (缺陷#15890)

  • partition_definition

    可以使用 partition_definition 子句 单独定义每个分区 构成本条款的各个部分如下:

    • PARTITION partition_name

      指定分区的逻辑名称。

    • VALUES

      对于范围分区,每个分区必须包含一个 VALUES LESS THAN 子句; 对于列表分区,您必须 VALUES IN 为每个分区 指定一个 子句。 这用于确定要在此分区中存储哪些行。 见分区类型的讨论 第23章, 分区 ,语法的例子。

    • [STORAGE] ENGINE

      MySQL的接受 [STORAGE] ENGINE 了这两个选项 PARTITION SUBPARTITION 目前,可以使用此选项的唯一方法是将所有分区或所有子分区设置为同一存储引擎,并且尝试为同一表中的分区或子分区设置不同的存储引擎将导致错误 ERROR 1469 (HY000):在此版本的MySQL中不允许分区中的处理程序组合

    • COMMENT

      可选 COMMENT 子句可用于指定描述分区的字符串。 例:

      评论='1999年之前的数据'
      

      分区注释的最大长度为1024个字符。

    • DATA DIRECTORY INDEX DIRECTORY

      DATA DIRECTORY 并且 INDEX DIRECTORY 可以用于指示分别存储该分区的数据和索引的目录。 无论是 data_dir index_dir 必须是绝对系统路径名。

      您必须有权 FILE 使用 DATA DIRECTORY INDEX DIRECTORY 分区选项。

      例:

      CREATE TABLE th(id INT,名称VARCHAR(30),adate DATE)
      按名单划分(年份(adate))
        分区p1999价值观(1995年,1999年,2003年)
          DATA DIRECTORY =' /var/appdata/95/data'
          INDEX DIRECTORY =' /var/appdata/95/idx',
        分区p2000价值观(1996年,2000年,2004年)
          DATA DIRECTORY =' /var/appdata/96/data'
          INDEX DIRECTORY =' /var/appdata/96/idx',
        分区p2001价值观(1997年,2001年,2005年)
          DATA DIRECTORY =' /var/appdata/97/data'
          INDEX DIRECTORY =' /var/appdata/97/idx',
        分区p2002价值观(1998年,2002年,2006年)
          DATA DIRECTORY =' /var/appdata/98/data'
          INDEX DIRECTORY =' /var/appdata/98/idx'
      );
      

      DATA DIRECTORY 并且 与用于 INDEX DIRECTORY CREATE TABLE 语句 table_option 子句 中的行为相同 MyISAM

      每个分区可以指定一个数据目录和一个索引目录。 如果未指定,则数据和索引默认存储在表的数据库目录中。

      DATA DIRECTORY INDEX DIRECTORY 选项将被忽略创建分区表是否 NO_DIR_IN_CREATE 有效。

    • MAX_ROWS MIN_ROWS

      可用于分别指定要在分区中存储的最大和最小行数。 为价值观 max_number_of_rows min_number_of_rows 必须为正整数。 与具有相同名称的表级选项一样,这些选项仅作为 服务器的 建议 而不是硬限制。

    • TABLESPACE

      可用于通过指定 InnoDB 为分区指定每个表 文件表空间 TABLESPACE `innodb_file_per_table` 所有分区必须属于同一存储引擎。

      不支持 InnoDB 表分区放在共享 InnoDB 表空间中。 共享表空间包括 InnoDB 系统表空间和通用表空间。

  • subpartition_definition

    分区定义可以可选地包含一个或多个 subpartition_definition 子句。 这些中的每一个至少包含 ,其中 是子分区的标识符。 除了替换 关键字with外 ,子分区定义的语法与分区定义的语法相同。 SUBPARTITION name name PARTITION SUBPARTITION

    子分区必须完成 HASH KEY ,并且只能在完成 RANGE LIST 分区。 请参见 第23.2.6节“子分区”

按生成的列进行分区

允许按生成的列进行分区。 例如:

CREATE TABLE t1(
  s1 INT,
  s2 INT AS(EXP(s1))已存储
按名单划分(第2条)(
  分区p1值(1)
);

分区将生成的列视为常规列,这使得可以对不允许进行分区的函数进行限制(请参见 第23.6.3节“对函数相关的分区限制” )。 上面的示例演示了此技术: EXP() 不能直接在 PARTITION BY 子句中使用,但 EXP() 允许 使用定义的生成列

13.1.20.1 CREATE TABLE语句保留

CREATE TABLE 创建表时,MySQL将存储 原始 语句,包括所有规范和表选项。 保留信息,以便在使用 ALTER TABLE 语句 更改存储引擎,排序规则或其他设置时 ,将保留指定的原始表选项。 这使您可以在 InnoDB MyISAM 类型 之间进行更改, 即使两个引擎支持的行格式不同。

因为保留了原始语句的文本,但是由于某些值和选项可以以静默方式重新配置的方式,活动表定义(可通过 DESCRIBE 或使用 SHOW TABLE STATUS )和表创建字符串(可通过 SHOW CREATE TABLE )可以报告不同的值。

对于 InnoDB 表, SHOW CREATE TABLE 以及 Create_options 报告 SHOW TABLE STATUS 显示 表使用 的实际 ROW_FORMAT KEY_BLOCK_SIZE 属性。 在以前的MySQL版本中,报告了这些属性的最初指定值。

13.1.20.2 CREATE TABLE创建的文件

对于 InnoDB 在每个表文件表空间或通用表空间中创建的表,表数据和关联索引存储在 数据库目录 中的 ibd文件 中。 InnoDB 在系统表空间中创建表,表数据和索引存储在 ibdata *文件 表示系统表空间。 innodb_file_per_table 选项控制是否默认情况下在每个表的文件表空间或系统表空间中创建表。 TABLESPACE 无论 innodb_file_per_table 设置 如何, 选项都可用于将表放在每个表的文件表空间,通用表空间或系统表空间中

对于 MyISAM 表,存储引擎会创建数据和索引文件。 因此,对于每个 MyISAM tbl_name ,有两个磁盘文件。

文件 目的
tbl_name.MYD 数据文件
tbl_name.MYI 索引文件

第16章, 备用存储引擎 ,描述了每个存储引擎为表示表而创建的文件。 如果表名包含特殊字符,则表文件的名称包含这些字符的编码版本,如 第9.2.3节“标识符到文件名的映射”中所述

13.1.20.3 CREATE TEMPORARY TABLE语法

您可以 TEMPORARY 在创建表时 使用该 关键字。 一个 TEMPORARY 表只在当前会话中可见,而当会话关闭时自动删除。 这意味着两个不同的会话可以使用相同的临时表名,而不会相互冲突或与现有 TEMPORARY 的同名 冲突 (在删除临时表之前,将隐藏现有表。)

InnoDB 不支持压缩的临时表。 innodb_strict_mode 启用(默认值), CREATE TEMPORARY TABLE 如果返回错误 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE 指定的。 如果 innodb_strict_mode 禁用,则发出警告,并使用非压缩行格式创建临时表。 innodb_file_per-table 选项不会影响 InnoDB 临时表 的创建

CREATE TABLE 导致隐式提交,除非与 TEMPORARY 关键字一起使用。 请参见 第13.3.3节“导致隐式提交的语句”

TEMPORARY 表与数据库(模式)的关系非常松散。 删除数据库不会自动删除 TEMPORARY 在该数据库中创建的 任何 表。 此外, TEMPORARY 如果使用 CREATE TABLE 语句中 的数据库名限定表名,则 可以 在不存在的数据库中 创建 在这种情况下,必须使用数据库名称限定对表的所有后续引用。

要创建临时表,您必须具有该 CREATE TEMPORARY TABLES 权限。 会话创建临时表后,服务器不会对表执行进一步的权限检查。 所述创建会话可以在桌子上进行任何操作,例如 DROP TABLE INSERT UPDATE ,或 SELECT

这种行为的一个含义是,即使当前用户没有创建它们的权限,会话也可以操纵其临时表。 假设当前用户没有 CREATE TEMPORARY TABLES 权限,但能够执行定义者上下文存储过程,该过程以具有 CREATE TEMPORARY TABLES 创建临时表 的用户的权限执行 该过程执行时,会话使用定义用户的权限。 该过程返回后,有效权限将恢复为当前用户的权限,该权限仍然可以查看临时表并对其执行任何操作。

您不能使用 CREATE TEMPORY TABLE ... LIKE 基于表 mysql 空间, InnoDB system tablespace( innodb_system )或常规表空间 中的 的定义来创建空表 此类表的表空间定义包括一个 TABLESPACE 属性, 属性定义表所在的表空间,并且上述表空间不支持临时表。 要根据此类表的定义创建临时表,请改用以下语法:

CREATE TEMPORARY TABLE new_tblSELECT * FROM orig_tblLIMIT 0;        
注意

自MySQL 8.0.13起,不推荐使用对 支持 TABLESPACE = innodb_file_per_table TABLESPACE = innodb_temporary 子句的 支持, 并将 CREATE TEMPORARY TABLE 在未来的MySQL版本中删除。

13.1.20.4 CREATE TABLE ... LIKE语法

用于 CREATE TABLE ... LIKE 根据另一个表的定义创建一个空表,包括原始表中定义的任何列属性和索引:

new_tbl表格一样orig_tbl;

使用与原始表相同的表存储格式版本创建副本。 SELECT 原始表上需要 权限。

LIKE 仅适用于基表,不适用于视图。

重要

您无法执行 CREATE TABLE CREATE TABLE ... LIKE LOCK TABLES 语句生效时执行。

CREATE TABLE ... LIKE 进行相同的检查 CREATE TABLE 这意味着如果当前SQL模式与创建原始表时生效的模式不同,则对于新模式,表定义可能被视为无效,并且语句将失败。

对于 CREATE TABLE ... LIKE ,目标表保留原始表中生成的列信息。

对于 CREATE TABLE ... LIKE ,目标表保留原始表中的表达式默认值。

对于 CREATE TABLE ... LIKE ,目标表保留 CHECK 原始表中的约束,但生成所有约束名称除外。

CREATE TABLE ... LIKE 不保留 为原始表或任何外键定义指定的 任何 DATA DIRECTORY INDEX DIRECTORY 表选项。

如果原始表是 TEMPORARY 表, CREATE TABLE ... LIKE 则不保留 TEMPORARY 要创建 TEMPORARY 目标表,请使用 CREATE TEMPORARY TABLE ... LIKE

mysql 表空间, InnoDB 系统表空间( innodb_system )或通用表空间中创建的表包含 TABLESPACE 表定义中 属性,该属性定义表所在的表空间。 由于临时回归, CREATE TABLE ... LIKE 保留 TABLESPACE 属性并在定义的表空间中创建表,而不管 innodb_file_per_table 设置 如何 要在 TABLESPACE 基于此类表的定义创建空表时 避免该 属性,请使用以下语法:

CREATE TABLE new_tblSELECT * FROM orig_tblLIMIT 0;        

13.1.20.5 CREATE TABLE ... SELECT语法

您可以通过在 SELECT 语句末尾 添加 语句 来创建另一个表 CREATE TABLE

CREATE TABLE new_tbl[AS] SELECT * FROM orig_tbl;

MySQL为其中的所有元素创建新列 SELECT 例如:

mysql> CREATE TABLE test (a INT NOT NULL AUTO_INCREMENT,
    - >         PRIMARY KEY (a), KEY(b))
    - >        ENGINE=MyISAM SELECT b,c FROM test2;

这将创建一个 MyISAM 表有三列, a b ,和 c ENGINE 选项是 CREATE TABLE 声明的 一部分 ,不应使用 SELECT ; 这会导致语法错误。 对于其他 CREATE TABLE 选项 也是如此 CHARSET

请注意, SELECT 语句中 的列 会附加到表的右侧,而不会重叠到表的右侧。 请看以下示例:

MySQL的> SELECT * FROM foo;
+ --- +
| n |
+ --- +
| 1 |
+ --- +

MySQL的> CREATE TABLE bar (m INT) SELECT n FROM foo;
查询OK,1行受影响(0.02秒)
记录:1个重复:0警告:0

MySQL的> SELECT * FROM bar;
+ ------ + --- +
| m | n |
+ ------ + --- +
| NULL | 1 |
+ ------ + --- +
1排(0.00秒)

对于表中的每一行 foo ,将插入一行, bar 其中 foo 包含新列 的值 和默认值。

在由此产生的表中 CREATE TABLE ... SELECT ,仅在 CREATE TABLE 部件中 命名的列 首先出现。 在两个部分中或仅在部件中命名的列在此 SELECT 之后。 SELECT 可以通过指定 CREATE TABLE 零件中 列来覆盖列 的数据类型

如果在将数据复制到表时发生任何错误,则会自动删除它而不会创建。

您可以在 SELECT by 之前 IGNORE REPLACE 指示如何处理复制唯一键值的行。 使用 IGNORE ,复制唯一键值上现有行的行将被丢弃。 使用 REPLACE 新行替换具有相同唯一键值的行。 如果既未 指定 IGNORE REPLACE 指定,则重复的唯一键值会导致错误。 有关更多信息,请参阅 IGNORE关键字和严格SQL模式的比较

因为 SELECT 无法始终确定 基础 语句 中行的顺序 CREATE TABLE ... IGNORE SELECT 并且 CREATE TABLE ... REPLACE SELECT 语句被标记为基于语句的复制不安全。 当使用基于语句的模式时,此类语句在错误日志中生成警告,并在使用 MIXED 模式 时使用基于行的格式写入二进制日志 另请参见 第17.2.1.1节“基于语句和基于行的复制的优点和缺点”

CREATE TABLE ... SELECT 不会自动为您创建任何索引。 这样做是为了使声明尽可能灵活。 如果要在创建的表中包含索引,则应在 SELECT 语句 之前指定这些索引

MySQL的> CREATE TABLE bar (UNIQUE (n)) SELECT n FROM foo;

对于 CREATE TABLE ... SELECT ,目标表不保留有关selected-from表中的列是否为生成列的信息。 SELECT 语句 一部分无法为目标表中的生成列分配值。

对于 CREATE TABLE ... SELECT ,目标表确实保留原始表中的表达式默认值。

可能会发生某些数据类型转换。 例如, AUTO_INCREMENT 不保留 属性, VARCHAR 列可以成为 CHAR 列。 再培训属性是 NULL (或 NOT NULL ),对于有他们这些列, CHARACTER SET COLLATION COMMENT ,和 DEFAULT 条款。

使用时创建表 CREATE TABLE ... SELECT ,请确保在查询中为任何函数调用或表达式设置别名。 如果不这样做,则该 CREATE 语句可能会失败或导致不合需要的列名。

CREATE TABLE artists_and_works
  SELECT artist.name,COUNT(work.artist_id)AS number_of_works
  来自艺术家LEFT JOIN的作品在artist.id = work.artist_id上
  GROUP BY artist.id;

您还可以在创建的表中显式指定列的数据类型:

CREATE TABLE foo(TINYINT NOT NULL)SELECT b + 1 AS FROM BAR;

因为 CREATE TABLE ... SELECT ,如果 IF NOT EXISTS 给定并且目标表存在,则不会向目标表中插入任何内容,并且不会记录该语句。

为确保二进制日志可用于重新创建原始表,MySQL不允许在此期间进行并发插入 CREATE TABLE ... SELECT

您不能将其 FOR UPDATE 用作 SELECT 声明中的 一部分 如果您尝试这样做,则该语句将失败。 CREATE TABLE new_table SELECT ... FROM old_table ...

13.1.20.6使用FOREIGN KEY约束

MySQL支持外键,它允许您跨表交叉引用相关数据,以及 外键约束 ,这有助于保持这种展开数据的一致性。 CREATE TABLE or ALTER TABLE 语句 中外键约束定义的基本语法 如下所示:

[CONSTRAINT [ symbol]]外键
    [ index_name](col_name,...)
    参考文献tbl_namecol_name,...)
    [ON DELETE reference_option]
    [ON UPDATE reference_option]

reference_option
    限制| CASCADE | SET NULL | 没有动作| 默认设置

index_name 表示外键ID。 index_name 如果子表上已经显式定义了可以支持外键的索引,则忽略 值。 否则,MySQL会隐式创建一个根据以下规则命名的外键索引:

  • 如果已定义, CONSTRAINT symbol 则使用 值。 否则,使用该 FOREIGN KEY index_name 值。

  • 如果既没有 CONSTRAINT symbol FOREIGN KEY index_name 定义,使用引用外键列的名称所产生的外键索引名。

外键定义符合以下条件:

  • 外键关系涉及 保存中心数据值 父表 ,以及具有 指向其父级的相同值 子表 FOREIGN KEY 子句在子表中指定。 父表和子表必须使用相同的存储引擎。 他们不能是 TEMPORARY 桌子。

    在MySQL 8.0中,创建外键约束需要 REFERENCES 父表 特权。

  • 外键和引用键中的相应列必须具有相似的数据类型。 整数类型的大小和符号必须相同 字符串类型的长度不必相同。 对于非二进制(字符)字符串列,字符集和排序规则必须相同。

  • 如果 foreign_key_checks 启用(默认设置),则在包含外键约束中使用的字符串列的表上不允许进行字符集转换。 第13.1.9节“ALTER TABLE语法”中 介绍了解决方法

  • MySQL需要外键和引用键的索引,以便外键检查可以快速,不需要表扫描。 在引用表中,必须有一个索引,其中外键列 以相同的顺序 列为 第一 列。 如果引用表不存在,则会自动在引用表上创建此索引。 如果您创建另一个可用于强制执行外键约束的索引,则可以稍后以静默方式删除此索引。 index_name 如果给出,则如前所述使用。

  • InnoDB 允许外键引用任何索引列或列组。 但是,在引用的表中,必须有一个索引,其中引用的列是 同一顺序 中的 第一 列。 InnoDB 还会考虑添加到索引的 隐藏列 (请参见 第15.6.2.1节“聚簇和二级索引” )。

    NDB 要求在作为外键引用的任何列上使用显式唯一键(或主键)。

  • 不支持外键列上的索引前缀。 这样做的一个结果是, BLOB 并且 TEXT 列不能包含在外键中,因为这些列上的索引必须始终包含前缀长度。

  • 如果 给出了 子句,则该 值(如果使用)在数据库中必须是唯一的。 重复 将导致类似于以下的 错误 ERROR 1022(2300):无法写入; 表'#sql-464_1'中的重复键 如果未给出该子句,或者 关键字 后面没有包含 a ,则MySQL使用外键索引名称直到MySQL 8.0.15,并在此后自动生成约束名称。 CONSTRAINT symbol symbol symbol symbol CONSTRAINT

  • InnoDB 当前不支持具有用户定义分区的表的外键。 这包括父表和子表。

    此限制不适用于 NDB KEY 存储引擎 LINEAR KEY 支持的唯一用户分区类型) 分区的表 NDB ; 这些可能具有外键引用或是这些引用的目标。

  • 对于 NDB 表, ON UPDATE CASCADE 不支持引用父表的主键的位置。

FOREIGN KEY 本节中的以下主题描述 约束使用的 其他方面

参考行动

本节介绍外键如何帮助保证 参照完整性

对于支持外键的存储引擎, 如果父表中没有匹配的候选 键值,则MySQL拒绝任何 尝试在子表中创建外键值的操作 INSERT UPDATE 操作。

UPDATE DELETE 操作影响父表中具有子表中匹配行的键值时,结果取决于 使用 子句 句子 指定 引用操作 MySQL支持关于要采取的操作的五个选项,如下所示: ON UPDATE ON DELETE FOREIGN KEY

  • CASCADE :从父表中删除或更新行,并自动删除或更新子表中的匹配行。 这两个 ON DELETE CASCADE ON UPDATE CASCADE 支持。 在两个表之间,不要定义多个 ON UPDATE CASCADE 子句, 这些 子句作用于父表或子表中的同一列。

    如果 FOREIGN KEY 在外键关系中的两个表上 定义了一个 子句 ,使两个表都成为父和子,则 必须 为另一个 子句 定义为一个 子句 定义的 子句 ON UPDATE CASCADE 子句,以便级联操作成功。 如果 仅为一个 子句 定义了一个 子句,则级联操作将失败并显示错误。 ON DELETE CASCADE FOREIGN KEY ON UPDATE CASCADE ON DELETE CASCADE FOREIGN KEY

    注意

    级联外键操作不会激活触发器。

  • SET NULL :从父表中删除或更新行,并将子表中的外键列设置为 NULL 支持 两个 ON DELETE SET NULL ON UPDATE SET NULL 子句。

    如果指定 SET NULL 操作,请 确保未将子表中的列声明为 NOT NULL

  • RESTRICT :拒绝父表的删除或更新操作。 指定 RESTRICT (或 NO ACTION )与省略 ON DELETE or ON UPDATE 子句 相同

  • NO ACTION :标准SQL中的关键字。 在MySQL中,相当于 RESTRICT 如果引用的表中存在相关的外键值,则MySQL服务器拒绝父表的删除或更新操作。 某些数据库系统具有延迟检查,并且 NO ACTION 是延迟检查。 在MySQL中,立即检查外键约束,因此 NO ACTION 也是 如此 RESTRICT

  • SET DEFAULT :这个动作由MySQL解析器认可,但两者 InnoDB NDB 拒绝包含表定义 ON DELETE SET DEFAULT ON UPDATE SET DEFAULT 条款。

对于 未指定 ON DELETE 或未 ON UPDATE 指定的,默认操作始终为 RESTRICT

MySQL支持表中一列与另一列之间的外键引用。 (列不能有自己的外键引用。)在这些情况下, 子表记录 实际上是指同一个表中的依赖记录。

在存储生成列外键约束不能使用 CASCADE SET NULL SET DEFAULT 作为 ON UPDATE 参照动作,也不能使用 SET NULL SET DEFAULT 作为 ON DELETE 参照动作。

在存储生成列的基本列外键约束不能使用 CASCADE SET NULL SET DEFAULT 作为 ON UPDATE ON DELETE 引用操作。

外键约束不能引用虚拟生成的列。

有关 InnoDB 外键和生成列的限制,请参见 第15.6.1.5节“InnoDB和FOREIGN KEY约束”

外键条款的例子

这是一个 通过单列外键 关联 parent child 的简单示例

CREATE TABLE父级(
    id INT NOT NULL,
    PRIMARY KEY(id)
)ENGINE = INNODB;

CREATE TABLE子(
    id INT,
    parent_id INT,
    INDEX par_ind(parent_id),
    FOREIGN KEY(parent_id)
        REFERENCES parent(id)
        ON DELETE CASCADE
)ENGINE = INNODB;

一个更复杂的示例,其中 product_order 表具有两个其他表的外键。 一个外键引用表中的两列索引 product 另一个引用表中的单列索引 customer

CREATE TABLE产品(
    category INT NOT NULL,id INT NOT NULL,
    价格DECIMAL,
    PRIMARY KEY(类别,id)
)ENGINE = INNODB;

CREATE TABLE客户(
    id INT NOT NULL,
    PRIMARY KEY(id)
)ENGINE = INNODB;

CREATE TABLE product_order(
    没有INT NOT NULL AUTO_INCREMENT,
    product_category INT NOT NULL,
    product_id INT NOT NULL,
    customer_id INT NOT NULL,

    PRIMARY KEY(不),
    INDEX(product_category,product_id),
    INDEX(customer_id),

    FOREIGN KEY(product_category,product_id)
      REFERENCES产品(类别,ID)
      在DELETE RESTRICT上更新级联,

    FOREIGN KEY(customer_id)
      参考客户(id)
)ENGINE = INNODB;
添加外键

您可以使用添加新的外键约束到现有表 ALTER TABLE 此语句显示与此语句的外键相关的语法:

ALTER TABLE tbl_name
    ADD [CONSTRAINT [ symbol]] FOREIGN KEY
    [ index_name](col_name,...)
    参考文献tbl_namecol_name,...)
    [ON DELETE reference_option]
    [ON UPDATE reference_option]

外键可以是自引用的(参考同一个表)。 使用时向表中添加外键约束时 ALTER TABLE 请记住首先创建所需的索引。

删除外键

您还可以使用 ALTER TABLE 此处显示的语法来删除外键:

ALTER TABLE tbl_nameDROP FOREIGN KEY fk_symbol;

如果 FOREIGN KEY 子句 CONSTRAINT 在创建外键时 包含 名称,则可以引用该名称以删除外键。 否则,在 fk_symbol 创建外键时在内部生成 值。 要在删除外键时找出符号值,请使用 SHOW CREATE TABLE 语句,如下所示:

MySQL的> SHOW CREATE TABLE ibtest11c\G
*************************** 1。排******************** *******
       表:ibtest11c
创建表:CREATE TABLE`ibtest11c`(
  `A`int(11)NOT NULL auto_increment,
  `D` int(11)NOT NULL默认'0',
  `B` varchar(200)NOT NULL default'',
  `C` varchar(175)默认为NULL,
  PRIMARY KEY(`A`,`D`,`B`),
  KEY`B`(`B`,`C`),
  KEY`C`(`C`),
  CONSTRAINT`0_38775` FOREIGN KEY(`A`,`D`)
参考文献`ibtest11a`(`A`,`D`)
在更新级联上删除级联,
  CONSTRAINT`0_38776` FOREIGN KEY(`B`,`C`)
参考文献`ibtest11a`(`B`,`C`)
ON UPATE CASCADE ON UPDATE CASCADE
)ENGINE = INNODB CHARSET = utf8mb4
1排(0.01秒)

MySQL的> ALTER TABLE ibtest11c DROP FOREIGN KEY `0_38775`;

ALTER TABLE 支持 在同一 语句中 添加和删​​除外键 ALTER TABLE ... ALGORITHM=INPLACE 但不支持 ALTER TABLE ... ALGORITHM=COPY

外键和其他MySQL语句

FOREIGN KEY ... REFERENCES ... 子句中的 表和列标识符 可以在反引号( ` )中 引用 或者, " 如果 ANSI_QUOTES 启用 SQL模式,则 可以使用 双引号( lower_case_table_names 还考虑 系统变量 的设置

您可以查看子表的外键定义作为 SHOW CREATE TABLE 语句 输出的一部分

SHOW CREATE TABLE tbl_name;

您还可以通过查询 INFORMATION_SCHEMA.KEY_COLUMN_USAGE 获取有关外键的信息

您可以 数据库中 找到有关 InnoDB INNODB_FOREIGN INNODB_FOREIGN_COLS 表中 使用的外键 INFORMATION_SCHEMA 信息。

mysqldump 在转储文件中生成正确的表定义,包括子表的外键。

为了更容易为具有外键关系的表重新加载转储文件, mysqldump会 自动在转储输出中包含一个语句,设置 foreign_key_checks 为0.这样可以避免在重新加载转储时必须按特定顺序重新加载表的问题。 也可以手动设置此变量:

mysql> SET foreign_key_checks = 0;
mysql> 
mysql>SOURCE dump_file_name;SET foreign_key_checks = 1;

这使您可以按任何顺序导入表,如果转储文件包含未正确为外键订购的表。 它还加快了进口操作。 设置 foreign_key_checks 为0,也可以是在忽略外键约束有用 LOAD DATA ALTER TABLE 操作。 但是,即使 foreign_key_checks = 0 MySQL不允许创建外键约束,其中列引用不匹配的列类型。 此外,如果表具有外键约束, ALTER TABLE 则不能用于更改表以使用其他存储引擎。 要更改存储引擎,必须先删除任何外键约束。

除非您这样做,否则不能 DROP TABLE FOREIGN KEY 约束 引用的表 发出 SET foreign_key_checks = 0 删除表时,也会删除用于创建该表的语句中定义的任何约束。

如果重新创建已删除的表,则它必须具有符合引用它的外键约束的定义。 它必须具有正确的列名和类型,并且必须在引用的键上具有索引,如前所述。 如果不满足这些,MySQL将返回错误1005并在错误消息中引用错误150,这意味着未正确形成外键约束。 类似地,如果 ALTER TABLE 由于错误150而失败,则意味着对于更改的表将错误地形成外键定义。

对于 InnoDB 表,您可以 InnoDB 通过检查输出来获得MySQL服务器中 最新 外键错误 的详细说明 SHOW ENGINE INNODB STATUS

MySQL根据需要将元数据锁扩展到由外键约束相关的表。 扩展元数据锁可防止冲突的DML和DDL操作在相关表上并发执行。 此功能还允许在修改父表时更新外键元数据。 在早期的MySQL版本中,子表所拥有的外键元数据无法安全更新。

如果显式锁定 LOCK TABLES 表,则会打开并隐式锁定由外键约束关联的任何表。 对于外键检查, LOCK TABLES READ 对相关表 执行共享只读锁( )。 对于级联更新, LOCK TABLES WRITE 对操作中涉及的相关表 采用无共享写锁( )。

外键和ANSI / ISO SQL标准

对于熟悉ANSI / ISO SQL标准的用户,请注意,没有存储引擎,包括 InnoDB ,识别或强制执行 MATCH 参照完整性约束定义中使用 子句。 使用explicit MATCH 子句不会产生指定的效果,也会 忽略 cause ON DELETE ON UPDATE 子句。 出于这些原因, MATCH 应该避免 指定

MATCH SQL标准中 子句控制 NULL 在与主键进行比较时如何处理复合(多列)外键中的值。 MySQL本质上实现了定义的语义 MATCH SIMPLE ,允许外键全部或部分 NULL 在这种情况下,允许插入包含此类外键的(子表)行,并且与引用的(父)表中的任何行都不匹配。 可以使用触发器实现其他语义。

此外,由于性能原因,MySQL要求对引用的列进行索引。 然而,该系统并不强制所引用的列是一个要求 UNIQUE 或声明 NOT NULL 对包含 NULL 值的 非唯一键或键的外键引用的处理 没有为诸如 UPDATE 或之类的 操作定义 DELETE CASCADE 建议您使用仅引用 UNIQUE (包括 PRIMARY )和 NOT NULL 键的外键。

此外,MySQL解析但忽略了 内联 REFERENCES 规范 (如SQL标准中所定义),其中引用被定义为列规范的一部分。 MySQL REFERENCES 仅在指定为单独 FOREIGN KEY 规范的 一部分时才 接受 子句 对于不支持外键(例如 MyISAM )的 存储引擎 ,MySQL Server会解析并忽略外键规范。

外键元数据

INFORMATION_SCHEMA.KEY_COLUMN_USAGE 表标识了具有约束的键列。 InnoDB INNODB_SYS_FOREIGN INNODB_SYS_FOREIGN_COLS 表中 可以找到 特定于 外键的 元数据

外键错误

如果涉及 InnoDB 的外键错误 (通常是MySQL服务器中的错误150), InnoDB 可以通过检查 SHOW ENGINE INNODB STATUS 输出 获得 有关最新 外键错误的 信息

警告

如果用户拥有所有父表的表级的特权, ER_NO_REFERENCED_ROW_2 ER_ROW_IS_REFERENCED_2 为外键操作错误信息公开有关父表的信息。 如果用户没有所有父表的表级权限,则会显示更多通用错误消息( ER_NO_REFERENCED_ROW ER_ROW_IS_REFERENCED )。

例外情况是,对于定义为使用 DEFINER 特权 执行的存储程序 ,评估特权的用户是程序 DEFINER 子句中 的用户 ,而不是调用用户。 如果该用户具有表级父表权限,则仍会显示父表信息。 在这种情况下,存储的程序创建者有责任通过包括适当的条件处理程序来隐藏信息。

13.1.20.7检查约束条件

在MySQL 8.0.16之前, CREATE TABLE 只允许以下限制版本的表 CHECK 约束语法,该语法被解析并被忽略:

检查(expr

从MySQL 8.0.16开始, CREATE TABLE 允许 CHECK 所有存储引擎 的表和列 约束 的核心功能 对于表约束和列约束, CREATE TABLE 允许以下 CHECK 约束语法:

[CONSTRAINT [ symbol]] CHECK(expr)[[NOT] ENFORCED]

optional symbol 指定约束的名称。 如果省略,MySQL将根据表名,文字 _chk_ 和序号(1,2,3,...)生成名称。 约束名称的最大长度为64个字符。 它们区分大小写,但不区分重音。

expr 将约束条件指定为布尔表达式,该表达式必须 为表的每一行 计算 TRUE UNKNOWN (对于 NULL 值)。 如果条件求值为 FALSE ,则失败并发生约束违规。 违规的影响取决于正在执行的语句,如本节后面所述。

可选的强制子句指示是否强制执行约束:

  • 如果省略或指定为 ENFORCED ,则创建并强制执行约束。

  • 如果指定为 NOT ENFORCED ,则创建约束但不强制执行。

CHECK 约束被指定为任一表约束或列约束:

  • 表约束不会出现在列定义中,并且可以引用任何表列或列。 允许前向引用到表定义中稍后出现的列。

  • 列约束出现在列定义中,并且只能引用该列。

考虑这个表定义:

CREATE TABLE t1
  检查(c1 <> c2),
  c1 INT CHECK(c1> 10),
  c2 INT CONSTRAINT c2_positive CHECK(c2> 0),
  c3 INT CHECK(c3 <100),
  CONSTRAINT c1_nonzero CHECK(c1 <> 0),
  检查(c1> c3)
);

该定义包括命名和未命名格式的表约束和列约束:

  • 第一个约束是表约束:它发生在任何列定义之外,因此它可以(并且确实)引用多个表列。 此约束包含对尚未定义的列的前向引用。 没有指定约束名称,因此MySQL生成一个名称。

  • 接下来的三个约束是列约束:每个约束都出现在列定义中,因此只能引用要定义的列。 其中一个约束是明确命名的。 MySQL为其他两个中的每一个生成一个名称。

  • 最后两个约束是表约束。 其中一个是明确命名的。 MySQL为另一个生成一个名称。

如上所述,MySQL为没有 CHECK 指定的 任何 约束 生成一个名称 要查看为上一个表定义生成的名称,请使用 SHOW CREATE TABLE

MySQL的> SHOW CREATE TABLE t1\G
*************************** 1。排******************** *******
       表:t1
创建表:CREATE TABLE`t1`(
  `c1` int(11)DEFAULT NULL,
  `c2` int(11)DEFAULT NULL,
  `c3` int(11)DEFAULT NULL,
  CONSTRAINT`c1_nonzero` CHECK((``c1` <> 0)),
  CONSTRAINT`c2_positive`检查((``c2`> 0)),
  约束`t1_chk_1`检查((``c1` <>`c2`)),
  约束`t1_chk_2`检查((``c1`> 10)),
  CONSTRAINT`t1_chk_3`检查((``c3` <100)),
  CONSTRAINT`t1_chk_4`检查((``c1`>`c3`))
)ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci

SQL标准指定所有类型的约束(主键,唯一索引,外键,检查)属于同一名称空间。 在MySQL中,每个约束类型每个模式(数据库)都有自己的命名空间。 因此, CHECK 每个模式的约束名称必须是唯一的; 同一模式中没有两个表可以共享 CHECK 约束名称。 (例外: TEMPORARY 表隐藏了一个 TEMPORARY 同名 的非 表,因此它也可以具有相同的 CHECK 约束名。)

使用表名开始生成约束名称有助于确保模式唯一性,因为表名在模式中也必须是唯一的。

CHECK 条件表达式必须遵守以下规则。 如果表达式包含不允许的构造,则会发生错误。

  • 允许使用非生成和生成的列,但具有 AUTO_INCREMENT 其他表中 属性和列的列 除外

  • 允许使用文字,确定性内置函数和运算符。 如果给定表中的相同数据,则多个调用产生相同的结果,而不是连接的用户,则函数是确定性的。 :那是不确定性和失败,这个定义功能的例子 CONNECTION_ID() CURRENT_USER() NOW()

  • 不允许存储函数和用户定义的函数。

  • 不允许存储过程和函数参数。

  • 不允许使用变量(系统变量,用户定义的变量和存储的程序局部变量)。

  • 不允许子查询。

约束中 使用的列禁止 外键引用操作( ON UPDATE ON DELETE CHECK 同样, CHECK 对外键引用操作中使用的列禁止约束。

CHECK 约束评估 INSERT UPDATE REPLACE LOAD DATA ,和 LOAD XML 语句并且如果约束评估为发生错误 FALSE 如果发生错误,则已应用的更改的处理因事务和非事务存储引擎而异,并且还取决于严格的SQL模式是否有效,如 严格SQL模式中所述

CHECK 约束评估 INSERT IGNORE UPDATE IGNORE LOAD DATA ... IGNORE ,和 LOAD XML ... IGNORE 语句,如果一个约束评估为出现警告 FALSE 将跳过任何违规行的插入或更新。

如果约束表达式求值为与声明的列类型不同的数据类型,则根据通常的MySQL类型转换规则对声明的类型进行隐式强制。 请参见 第12.2节“表达式评估中的类型转换” 如果类型转换失败或导致精度损失,则会发生错误。

注意

约束表达式评估使用在评估时生效的SQL模式。 如果表达式的任何组件依赖于SQL模式,则表的不同用法可能会出现不同的结果,除非在所有使用过程中SQL模式都相同。

13.1.20.8无声列规范更改

在某些情况下,MySQL会默认地更改列规范 CREATE TABLE 或在 ALTER TABLE 语句中 给出的规范 这些可能是对数据类型,与数据类型关联的属性或索引规范的更改。

所有更改都受内部行大小限制65,535字节的限制,这可能会导致某些数据类型更改尝试失败。 请参见 第C.10.4节“表列数和行大小的限制”

  • 列,其一部分 PRIMARY KEY 是由 NOT NULL 即使没有声明的方式。

  • 创建表时, 会自动删除尾随空格 ENUM SET 成员值。

  • MySQL将其他SQL数据库供应商使用的某些数据类型映射到MySQL类型。 请参见 第11.10节“使用其他数据库引擎中的数据类型”

  • 如果包含一个 USING 子句来指定给定存储引擎不允许的索引类型,但引擎可以使用另一种可用的索引类型而不影响查询结果,则引擎使用可用类型。

  • 如果未启用严格SQL模式,则会 VARCHAR 将长度指定大于65535 TEXT VARBINARY 转换为 ,并将 长度指定大于65535 列转换为 BLOB 否则,在这两种情况下都会发生错误。

  • 指定 CHARACTER SET binary 字符数据类型 属性会导致将列创建为相应的二进制数据类型: CHAR 变为 BINARY VARCHAR 变为 VARBINARY TEXT 变为 BLOB 对于 ENUM SET 数据类型,不会发生这种情况; 它们是按声明创建的。 假设您使用此定义指定表:

    创建表t
      c1 VARCHAR(10)CHARACTER SET二进制,
      c2 TEXT CHARACTER SET二进制,
      c3 ENUM('a','b','c')CHARACTER SET二进制
    );
    

    结果表具有以下定义:

    创建表t
      c1 VARBINARY(10),
      c2 BLOB,
      c3 ENUM('a','b','c')CHARACTER SET二进制
    );
    

要查看MySQL是否使用了您指定的数据类型以外的数据类型,请 在创建或更改表后 发出 DESCRIBE SHOW CREATE TABLE 声明。

如果使用 myisampack 压缩表, 可能会发生某些其他数据类型更改 请参见 第16.2.3.3节“压缩表特性”

13.1.20.9 CREATE TABLE和Generated Columns

CREATE TABLE 支持生成列的规范。 生成列的值是根据列定义中包含的表达式计算的。

NDB 存储引擎 也支持生成的列

下面的简单示例显示了一个表,该表存储了 sidea 三角形中 sideb 的直角三角形的长度,并计算了斜边的长度 sidec (其他边的平方和的平方根):

CREATE TABLE三角形(
  sidea DOUBLE,
  sideb DOUBLE,
  sidec DOUBLE AS(SQRT(sidea * sidea + sideb * sideb))
);
插入三角形(sidea,sideb)VALUES(1,1),(3,4),(6,8);

从表中选择会产生以下结果:

MySQL的> SELECT * FROM triangle;
+ ------- ------- + + -------------------- +
| sidea | sideb | sidec |
+ ------- ------- + + -------------------- +
| 1 | 1 | 1.4142135623730951 |
| 3 | 4 | 5 |
| 6 | 8 | 10 |
+ ------- ------- + + -------------------- +

使用该 triangle 表的 任何应用程序 都可以访问斜边值,而无需指定计算它们的表达式。

生成的列定义具有以下语法:

col_name data_type[GENERATED ALWAYS] AS(expr
  [VIRTUAL | 存储] [NOT NULL | 空值]
  [UNIQUE [KEY]] [[PRIMARY] KEY]
  [评论' string']

AS (expr) 表示生成列并定义用于计算列值的表达式。 AS 之前 GENERATED ALWAYS 可以使列的生成性质更明确。 表达式中允许或禁止的构造将在后面讨论。

VIRTUAL STORED 关键字表示列的值的存储方式,其具有用于使用列含义:

  • VIRTUAL :不存储列值,但在任何 BEFORE 触发器 之后立即读取行时计算列值 虚拟列不占用存储空间。

    InnoDB 支持虚拟列上的二级索引。 请参见 第13.1.20.10节“二级索引和生成的列”

  • STORED :插入或更新行时,将评估和存储列值。 存储的列确实需要存储空间并且可以编制索引。

VIRTUAL 如果两个关键字都未指定,则 默认为

允许 在表格中 混合 VIRTUAL STORED 列。

可以给出其他属性以指示列是否被索引或可以是 NULL ,或者提供评论。

生成的列表达式必须遵守以下规则。 如果表达式包含不允许的构造,则会发生错误。

  • 允许使用文字,确定性内置函数和运算符。 如果给定表中的相同数据,则多个调用产生相同的结果,而不是连接的用户,则函数是确定性的。 :那是不确定性和失败,这个定义功能的例子 CONNECTION_ID() CURRENT_USER() NOW()

  • 不允许存储函数和用户定义的函数。

  • 不允许存储过程和函数参数。

  • 不允许使用变量(系统变量,用户定义的变量和存储的程序局部变量)。

  • 不允许子查询。

  • 生成的列定义可以引用其他生成的列,但只能引用表定义中较早出现的列。 生成的列定义可以引用表中的任何基本(非生成)列,无论其定义是早期还是稍后发生。

  • AUTO_INCREMENT 属性不能用于生成的列定义。

  • 一个 AUTO_INCREMENT 列不能用作在生成的列定义的基柱。

  • 如果表达式求值导致截断或向函数提供不正确的输入,则 CREATE TABLE 语句将终止并显示错误,并拒绝DDL操作。

如果表达式求值为与声明的列类型不同的数据类型,则根据通常的MySQL类型转换规则对声明的类型进行隐式强制。 请参见 第12.2节“表达式评估中的类型转换”

注意

表达式评估使用SQL模式在评估时生效。 如果表达式的任何组件依赖于SQL模式,则表的不同用法可能会出现不同的结果,除非在所有使用过程中SQL模式都相同。

对于 CREATE TABLE ... LIKE ,目标表保留原始表中生成的列信息。

对于 CREATE TABLE ... SELECT ,目标表不保留有关selected-from表中的列是否为生成列的信息。 SELECT 语句 一部分无法为目标表中的生成列分配值。

允许按生成的列进行分区。 请参阅 表分区

在存储生成列外键约束不能使用 CASCADE SET NULL SET DEFAULT 作为 ON UPDATE 参照动作,也不能使用 SET NULL SET DEFAULT 作为 ON DELETE 参照动作。

在存储生成列的基本列外键约束不能使用 CASCADE SET NULL SET DEFAULT 作为 ON UPDATE ON DELETE 引用操作。

外键约束不能引用虚拟生成的列。

有关 InnoDB 外键和生成列的限制,请参见 第15.6.1.5节“InnoDB和FOREIGN KEY约束”

触发器不能用于 或用于 引用生成的列。 NEW.col_name OLD.col_name

对于 INSERT ,, REPLACE UPDATE ,如果生成的列明确插入,替换或更新,则唯一允许的值为 DEFAULT

视图中生成的列被视为可更新,因为可以为其分配。 但是,如果明确更新此类列,则唯一允许的值为 DEFAULT

生成的列有几个用例,例如:

  • 虚拟生成的列可用作简化和统一查询的方法。 可以将复杂条件定义为生成列,并从表上的多个查询引用,以确保它们全部使用完全相同的条件。

  • 存储生成的列可以用作物化缓存,用于复杂的条件,这些条件在运行中计算成本很高。

  • 生成的列可以模拟功能索引:使用生成的列定义功能表达式并对其进行索引。 这对于处理无法直接索引的类型列(例如 JSON 列) 非常有用 ; 有关详细示例, 请参阅 索引生成的列以提供JSON列索引

    对于存储的生成列,这种方法的缺点是值存储两次; 一次作为生成列的值,一次作为索引。

  • 如果生成的列已建立索引,则优化程序将识别与列定义匹配的查询表达式,并在查询执行期间根据需要使用列中的索引,即使查询未按名称直接引用该列也是如此。 有关详细信息,请参见 第8.3.11节“生成列索引的优化程序使用”

例:

假设一个表 t1 包含 first_name last_name 列,并且该应用程序经常使用如下表达式构造全名:

SELECT CONCAT(first_name,'',last_name)AS full_name FROM t1;

避免编写出表达的一种方法是创建一个视图 v1 t1 ,其通过使它们简化的应用程序来选择 full_name 的情况下直接使用的表达式:

创建视图v1 AS
SELECT *,CONCAT(first_name,'',last_name)AS full_name FROM t1;

SELECT full_name FROM v1;

生成的列还使应用程序可以 full_name 直接 选择 ,而无需定义视图:

CREATE TABLE t1(
  first_name VARCHAR(10),
  last_name VARCHAR(10),
  full_name VARCHAR(255)AS(CONCAT(first_name,'',last_name))
);

SELECT full_name FROM t1;

13.1.20.10二级索引和生成的列

InnoDB 支持虚拟生成列上的二级索引。 不支持其他索引类型。 在虚拟列上定义的辅助索引有时被称为 虚拟索引

可以在一个或多个虚拟列上或在虚拟列和常规列或存储的生成列的组合上创建二级索引。 包含虚拟列的二级索引可以定义为 UNIQUE

在虚拟生成列上创建辅助索引时,生成的列值将在索引的记录中实现。 如果索引是 覆盖索引 (包括查询检索的所有列的 索引 ),则从索引结构中的具体化值中检索生成的列值,而不是 在运行中 计算

有额外的费用写入使用辅助索引时,在虚拟列,由于在计算过程中物化辅助索引记录虚拟列值时,进行考虑 INSERT UPDATE 操作。 即使有额外的写入成本,虚拟列上的二级索引可能优于生成的 存储 列,这些列在聚簇索引中具体化,从而导致需要更多磁盘空间和内存的更大表。 如果未在虚拟列上定义辅助索引,则会有额外的读取成本,因为每次检查列的行时都必须计算虚拟列值。

索引虚拟列的值是MVCC记录的,以避免在回滚期间或清除操作期间对生成的列值进行不必要的重新计算。 记录的值的数据长度是由767个字节的索引关键字限制的限制 COMPACT REDUNDANT 排格式,并为3072个字节 DYNAMIC COMPRESSED 列格式。

在虚拟列上添加或删除辅助索引是就地操作。

索引生成的列以提供JSON列索引

如其他地方所述, JSON 列不能直接索引。 要创建间接引用此类列的索引,可以定义生成的列以提取应编制索引的信息,然后在生成的列上创建索引,如以下示例所示:

mysql> CREATE TABLE jemp (
    - >      c JSON,
    - >      g INT GENERATED ALWAYS AS (c->"$.id")),
    - >      INDEX i (g)
    - >);
查询OK,0行受影响(0.28秒)

MySQL的> INSERT INTO jemp (c) VALUES
     >    ('{"id": "1", "name": "Fred"}'), ('{"id": "2", "name": "Wilma"}'),
     >   ('{"id": "3", "name": "Barney"}'), ('{"id": "4", "name": "Betty"}');
查询OK,4行受影响(0.04秒)
记录:4个重复:0警告:0

mysql SELECT c->>"$.name" AS name
     >>     FROM jemp WHERE g > 2;
+ -------- +
| 名字|
+ -------- +
| 巴尼|
| 贝蒂|
+ -------- +
2行(0.00秒)

mysql EXPLAIN SELECT c->>"$.name" AS name
     >>    FROM jemp WHERE g > 2\G
*************************** 1。排******************** *******
           id:1
  select_type:SIMPLE
        桌子:jemp
   分区:NULL
         类型:范围
possible_keys:i
          关键:我
      key_len:5
          ref:NULL
         行:2
     过滤:100.00
        额外:使用在哪里
1排,1警告(0.00秒)

MySQL的> SHOW WARNINGS\G
*************************** 1。排******************** *******
  等级:注意
   代码:1003
消息:/ * select#1 * / select json_unquote(json_extract(`test` .jemp``c`,'$。name'))
AS`name`来自`test` .jemp` where(`test` .jemp``g`> 2)
1排(0.00秒)

(我们已经包装了此示例中最后一个语句的输出以适合查看区域。)

当您 EXPLAIN SELECT 包含一个或多个使用 -> or ->> 运算符的 表达式的其他SQL语句上使用时 ,这些表达式将使用 JSON_EXTRACT() 和(如果需要) 转换为其等效项 JSON_UNQUOTE() ,如此处 SHOW WARNINGS 紧接此 EXPLAIN 语句 后面 的输出中所示

mysql EXPLAIN SELECT c->>"$.name"
     >>FROM jemp WHERE g > 2 ORDER BY c->"$.name"\G
*************************** 1。排******************** *******
           id:1
  select_type:SIMPLE
        桌子:jemp
   分区:NULL
         类型:范围
possible_keys:i
          关键:我
      key_len:5
          ref:NULL
         行:2
     过滤:100.00
        额外:使用在哪里; 使用filesort
1排,1警告(0.00秒)

MySQL的> SHOW WARNINGS\G
*************************** 1。排******************** *******
  等级:注意
   代码:1003
消息:/ * select#1 * / select json_unquote(json_extract(`test` .jemp``c`,'$。name'))AS
`c  -  >>“$。name”`来自`test` .jemp` where(`test` .jemp``g`> 2)order by
json_extract(`test`.`jemp`.`c`, '$。名称')
1排(0.00秒)

有关 其他信息和示例, 请参阅 -> ->> 运算符 的说明 JSON_EXTRACT() 以及 JSON_UNQUOTE() 函数 函数的说明。

此技术还可用于提供间接引用无法直接索引的其他类型列的索引,例如 GEOMETRY 列。

NSON集群中的JSON列和间接索引

根据以下条件,还可以在MySQL NDB Cluster中使用JSON列的间接索引:

  1. NDB JSON 内部 处理 列值作为 BLOB 这意味着任何 NDB 具有一个或多个JSON列的表必须具有主键,否则它不能记录在二进制日志中。

  2. NDB 存储引擎不支持虚拟列的索引。 由于生成列的默认值为 VIRTUAL ,因此必须明确指定要将间接索引应用于的生成列 STORED

CREATE TABLE 用于创建 jempn 此处所示 表格 语句 jemp 前面显示 表格的 一个版本 ,其修改使其与 NDB 以下 内容兼容

CREATE TABLE jempn(
  a BIGINT(20)NOT NULL AUTO_INCREMENT PRIMARY KEY,
  c JSON DEFAULT NULL,
  g INT GENERATED ALWAYS AS(c  - >“$。name”)STORED,
  INDEX i(g)
)ENGINE = NDB;

我们可以使用以下 INSERT 语句 填充此表

插入jempn(a,c)VALUES   
  (NULL,'{“id”:“1”,“name”:“Fred”}'), 
  (NULL,'{“id”:“2”,“name”:“Wilma”}'),   
  (NULL,'{“id”:“3”,“name”:“Barney”}'), 
  (NULL,'{“id”:“4”,“name”:“Betty”}');

现在 NDB 可以使用索引 i ,如下所示:

MySQL的> EXPLAIN SELECT c->>"$.name" AS name         
          FROM jempn WHERE g > 2\G
*************************** 1。排******************** *******
           id:1
  select_type:SIMPLE
        桌子:jempn
   分区:p0,p1
         类型:范围
possible_keys:i
          关键:我
      key_len:5
          ref:NULL
         行:3
     过滤:100.00
        额外:使用推送条件的地方(`test` .jempn``g`> 2)
1排,1警告(0.00秒)

MySQL的> SHOW WARNINGS\G
*************************** 1。排******************** *******
  等级:注意
   代码:1003
消息:/ *选择#1 * /选择
json_unquote(json_extract(`test` .jempn``c`,'$。name'))AS`name`来自
`test``jempn` where(`test` .jempn``g`> 2)  
1排(0.00秒)

您应该记住,存储的生成列使用 DataMemory ,并且此 上的索引使用 IndexMemory

13.1.20.11设置NDB_TABLE选项

在MySQL NDB Cluster中, CREATE TABLE 或者 ALTER TABLE 语句中 的表注释 也可以用于指定一个 NDB_TABLE 选项,该选项由一个或多个名称 - 值对组成,如果需要,在字符串后面用逗号分隔 NDB_TABLE= 此处显示了名称和值语法的完整语法:

COMMENT =“NDB_TABLE = ndb_table_option[,ndb_table_option[,...]]”

ndb_table_option
    NOLOGGING = {1 | 0}
  | READ_BACKUP = {1 | 0}
  | PARTITION_BALANCE = {FOR_RP_BY_NODE | FOR_RA_BY_NODE | FOR_RP_BY_LDM
                      | FOR_RA_BY_LDM | FOR_RA_BY_LDM_X_2
                      | FOR_RA_BY_LDM_X_3 | FOR_RA_BY_LDM_X_4}
  | FULLY_REPLICATED = {1 | 0}

引用的字符串中不允许使用空格。 该字符串不区分大小写。

NDB 可以在这几个段落中更详细地描述以这种方式设置为注释的一部分 的四个 表选项。

NOLOGGING :使用1对应已 ndb_table_no_logging 启用,但没有实际效果。 作为占位符提供,主要是为了完整的 ALTER TABLE 陈述。

READ_BACKUP :将此选项设置为1与 ndb_read_backup 启用时 具有相同的效果 ; 可以从任何副本中读取。 您可以 READ_BACKUP 使用 ALTER TABLE 类似于以下所示 语句 在线 设置 现有表

ALTER TABLE ... ALGORITHM = INPLACE,COMMENT =“NDB_TABLE = READ_BACKUP = 1”;

ALTER TABLE ... ALGORITHM = INPLACE,COMMENT =“NDB_TABLE = READ_BACKUP = 0”;

有关该 ALGORITHM 选项的 更多信息 ALTER TABLE ,请参见 第22.5.14节“使用NDB簇中的ALTER TABLE进行联机操作”

PARTITION_BALANCE :提供对分区的分配和放置的额外控制。 支持以下四种方案:

  1. FOR_RP_BY_NODE :每个节点一个分区。

    每个节点上只有一个LDM存储主分区。 每个分区都存储在所有节点上的相同LDM(相同ID)中。

  2. FOR_RA_BY_NODE :每个节点组一个分区。

    每个节点都存储一个分区,可以是主副本,也可以是备份副本。 每个分区都存储在所有节点上的相同LDM中。

  3. FOR_RP_BY_LDM :每个节点上每个LDM的一个分区; 默认。

    这与MySQL NDB Cluster 7.5.2之前的行为相同,除了稍微不同的分区到LDM的映射,从LDM 0开始并为每个节点组放置一个分区,然后转到下一个LDM。

    如果 READ_BACKUP 设置为1,则 使用此设置

  4. FOR_RA_BY_LDM :每个节点组中每个LDM一个分区。

    这些分区可以是主分区或备份分区。

  5. FOR_RA_BY_LDM_X_2 :每个节点组中每个LDM有两个分区。

    这些分区可以是主分区或备份分区。

  6. FOR_RA_BY_LDM_X_3 :每个节点组中每个LDM有三个分区。

    这些分区可以是主分区或备份分区。

  7. FOR_RA_BY_LDM_X_4 :每个节点组中每个LDM有四个分区。

    这些分区可以是主分区或备份分区。

PARTITION_BALANCE 是用于设置每个表的分区数的首选接口。 MAX_ROWS 不推荐 使用 强制分区数,但继续支持向后兼容; 它将在MySQL NDB Cluster的未来版本中删除。 (Bug#81759,Bug#23544301)

FULLY_REPLICATED 控制表是否完全复制,即每个数据节点是否具有表的完整副本。 要启用表的完全复制,请使用 FULLY_REPLICATED=1

也可以使用 ndb_fully_replicated 系统变量 控制此设置 将其设置为 ON 默认情况下为所有新 NDB 启用该选项 ; 默认是 OFF ndb_data_node_neighbour 系统变量也可用于完全复制表,以确保当被访问的完全复制表中,我们访问的是本地本MySQL服务器的数据节点。

此处显示了在 CREATE TABLE 创建 NDB 时使用此类注释 语句 示例

的MySQL> CREATE TABLE t1 (
     >      c1 INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
     >      c2 VARCHAR(100),
     >      c3 VARCHAR(100) )
     >ENGINE=NDB
     >
COMMENT="NDB_TABLE=READ_BACKUP=0,PARTITION_BALANCE=FOR_RP_BY_NODE";

评论显示为输出的一部分 SHOW CREATE TABLE 查询文本也可以从查询MySQL信息模式 TABLES 表中获得,如下例所示:

mysql SELECT TABLE_NAME, TABLE_SCHEMA, TABLE_COMMENT
     >>FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME="t1";
+ ------------ + -------------- + --------------------- ------------------------------------- +
| TABLE_NAME | TABLE_SCHEMA | TABLE_COMMENT |
+ ------------ + -------------- + --------------------- ------------------------------------- +
| t1 | c | NDB_TABLE = READ_BACKUP = 0,PARTITION_BALANCE = FOR_RP_BY_NODE |
| t1 | d | |
+ ------------ + -------------- + --------------------- ------------------------------------- +
2行(0.00秒)

表的 ALTER TABLE 语句 也支持此注释语法 NDB 请记住,使用的表注释 ALTER TABLE 替换了表可能具有的任何现有注释。

MySQL的> ALTER TABLE t1 COMMENT="NDB_TABLE=PARTITION_BALANCE=FOR_RA_BY_NODE";
查询OK,0行受影响(0.40秒)
记录:0重复:0警告:0

mysql SELECT TABLE_NAME, TABLE_SCHEMA, TABLE_COMMENT
     >>FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME="t1";
+ ------------ + -------------- + --------------------- ----------------------------- +
| TABLE_NAME | TABLE_SCHEMA | TABLE_COMMENT |
+ ------------ + -------------- + --------------------- ----------------------------- +
| t1 | c | NDB_TABLE = PARTITION_BALANCE = FOR_RA_BY_NODE |
| t1 | d | |
+ ------------ + -------------- + --------------------- ----------------------------- +
2行(0.01秒)

您还 PARTITION_BALANCE 可以在 ndb_desc 的输出中 看到该 选项 的值 ndb_desc 还显示是否 为表设置 READ_BACKUP FULLY_REPLICATED 选项。 有关更多信息,请参阅此程序的说明。

因为该 READ_BACKUP 值未被转移到 ALTER TABLE 语句 设置的新注释 ,所以不再使用SQL来检索先前为其设置的值。 为防止这种情况发生,建议您保留现有注释字符串中的任何此类值,如下所示:

mysql SELECT TABLE_NAME, TABLE_SCHEMA, TABLE_COMMENT
     >>FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME="t1";
+ ------------ + -------------- + --------------------- ------------------------------------- +
| TABLE_NAME | TABLE_SCHEMA | TABLE_COMMENT |
+ ------------ + -------------- + --------------------- ------------------------------------- +
| t1 | c | NDB_TABLE = READ_BACKUP = 0,PARTITION_BALANCE = FOR_RP_BY_NODE |
| t1 | d | |
+ ------------ + -------------- + --------------------- ------------------------------------- +
2行(0.00秒)

MySQL的> ALTER TABLE t1 COMMENT="NDB_TABLE=READ_BACKUP=0,PARTITION_BALANCE=FOR_RA_BY_NODE";
查询OK,0行受影响(1.56秒)
记录:0重复:0警告:0

mysql SELECT TABLE_NAME, TABLE_SCHEMA, TABLE_COMMENT
     >>FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME="t1";
+ ------------ + -------------- + --------------------- ------------------------------------------- +
| TABLE_NAME | TABLE_SCHEMA | TABLE_COMMENT |
+ ------------ + -------------- + --------------------- ------------------------------------------- +
| t1 | c | NDB_TABLE = READ_BACKUP = 0,PARTITION_BALANCE = FOR_RA_BY_NODE |
| t1 | d | |
+ ------------ + -------------- + --------------------- ------------------------------------------- +
2行(0.01秒)

13.1.21 CREATE TABLESPACE语法

创建[UNDO] TABLESPACE tablespace_name

  InnoDB和NDB: 
    [添加数据文件'file_name']

  仅限InnoDB:
    [FILE_BLOCK_SIZE =值]
    [ENCRYPTION [=] {'Y'| 'N'}]

  仅限NDB: 
    使用LOGFILE GROUPlogfile_group
    [EXTENT_SIZE [=]extent_size]
    [INITIAL_SIZE [=] initial_size]
    [AUTOEXTEND_SIZE [=] autoextend_size]
    [MAX_SIZE [=] max_size]
    [NODEGROUP [=] nodegroup_id]
    [等待]
    [评论[=]'string ']

  InnoDB和NDB: 
    [ENGINE [=]engine_name]

该语句用于创建表空间。 精确的语法和语义取决于所使用的存储引擎。 在标准MySQL版本中,这始终是一个 InnoDB 表空间。 MySQL NDB Cluster还支持使用 NDB 存储引擎的 表空间

InnoDB的注意事项

CREATE TABLESPACE 语法用于创建常规表空间或撤消表空间。 UNDO 必须指定MySQL 8.0.14中引入 关键字以创建撤消表空间。

通用表空间是共享表空间。 它可以容纳多个表,并支持所有表行格式。 可以在相对于或独立于数据目录的位置创建常规表空间。

创建 InnoDB 通用表空间后,使用 将表添加到表空间。 有关更多信息,请参见 第15.6.3.3节“常规表空间” CREATE TABLE tbl_name ... TABLESPACE [=] tablespace_name ALTER TABLE tbl_name TABLESPACE [=] tablespace_name

撤消表空间包含撤消日志。 通过指定完全限定的数据文件路径,可以在选定的位置创建撤消表空间。 有关更多信息,请参见 第15.6.3.4节“撤消表空间”

NDB群集的注意事项

此语句用于创建表空间,该表空间可包含一个或多个数据文件,为NDB集群磁盘数据表提供存储空间(请参见 第22.5.13节“NDB集群磁盘数据表” )。 使用此语句创建一个数据文件并将其添加到表空间。 可以使用该 ALTER TABLESPACE 语句 将其他数据文件添加到表空间 (请参见 第13.1.10节“ALTER TABLESPACE语法” )。

注意

所有NDB Cluster Disk Data对象共享相同的命名空间。 这意味着 必须唯一地命名 每个磁盘数据对象 (而不仅仅是给定类型的每个磁盘数据对象)。 例如,您不能拥有具有相同名称的表空间和日志文件组,或者具有相同名称的表空间和数据文件。

UNDO 必须将 一个或多个 日志文件 的日志文件组 分配给要使用该 USE LOGFILE GROUP 子句 创建的表空间 logfile_group 必须是使用创建的现有日志文件组 CREATE LOGFILE GROUP (请参见 第13.1.16节“CREATE LOGFILE GROUP语法” )。 多个表空间可能使用相同的日志文件组进行 UNDO 日志记录。

设置 EXTENT_SIZE 或时 INITIAL_SIZE ,您可以选择使用一个字母的缩写来表示一个数量级的数字,类似于中使用的那些 my.cnf 通常,这是字母之一 M (兆字节)或 G (千兆字节)。

INITIAL_SIZE 并按 EXTENT_SIZE 以下方式进行四舍五入:

  • EXTENT_SIZE 向上舍入到最近的32K的整数倍。

  • INITIAL_SIZE 向下 舍入 到最近的32K的整数倍; 此结果向上舍入到最接近的整数倍 EXTENT_SIZE (在任何舍入后)。

刚才描述的舍入是明确完成的,当执行任何这样的舍入时,MySQL服务器会发出警告。 NDB内核还使用舍入值来计算 INFORMATION_SCHEMA.FILES 列值和其他用途。 但是,为避免出现意外结果,我们建议您在指定这些选项时始终使用32K的整数倍。

CREATE TABLESPACE 与使用 ENGINE [=] NDB ,表空间和相关联的数据文件的每一个数据群集节点上创建。 您可以通过查询 INFORMATION_SCHEMA.FILES 来验证数据文件是否已创建并获取有关它们的信息 (请参阅本节后面的示例。)

(参见 第25.11节“INFORMATION_SCHEMA文件表” 。)

选项

  • ADD DATAFILE :定义表空间数据文件的名称。 ADD DATAFILE 创建撤消表空间时需要 子句。 否则,从MySQL 8.0.14开始它是可选的。

    一个 InnoDB 表空间仅支持单个数据文件,其名称必须包括 .ibd 扩展名。 NDB Cluster表空间支持多个数据文件,这些文件可以包含任何合法的文件名; 通过使用 ALTER TABLESPACE 语句 创建NDB Cluster表空间后,可以将更多数据文件添加到NDB Cluster表空间

    要将常规表空间数据文件放在数据目录之外的位置,请包括完全限定的路径或相对于数据目录的路径。 撤消表空间只允许使用完全限定的路径。 如果未指定路径,则会在数据目录中创建常规表空间。 在未指定路径的情况下创建的撤消表空间将在 innodb_undo_directory 变量 定义的目录中创建 如果 innodb_undo_directory 变量未定义,则在数据目录中创建撤消表空间。

    不支持在数据目录下的子目录中创建通用表空间,以避免与隐式创建的每表文件表空间冲突。 在数据目录之外创建通用表空间或撤消表空间时,该目录必须存在,并且必须 InnoDB 在创建表空间之前 知道 要使目录已知 InnoDB ,请将其添加到 innodb_directories 值或其值附加到 innodb_directories 的变量之一 innodb_directories 是一个只读变量。 配置它需要重新启动服务器。

    file_name ,包括任何指定的路径,必须是单或双引号引起来。 文件名(不包括文件扩展名)和目录名的长度必须至少为一个字节。 不支持零长度文件名和目录名。

    如果 ADD DATAFILE 在创建表空间时未指定子句,则会隐式创建具有唯一文件名的表空间数据文件。 唯一文件名是128位UUID,格式化为由破折号( aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee 分隔的五组十六进制数字 如果存储引擎需要,则添加文件扩展名。 一个 .ibd 文件的扩展名被添加为 InnoDB 一般的表空间的数据文件。 在复制环境中,在主服务器上创建的数据文件名与在从服务器上创建的数据文件名不同。

    从MySQL 8.0.17开始,该 ADD DATAFILE 子句在创建 InnoDB 表空间 时不允许循环目录引用 例如, /../ 不允许以下语句中 的循环目录reference( ):

    CREATE TABLESPACE ts1添加DATAFILE ts1.ibd' any_directory/../ts1.ibd';
    

    Linux上存在此限制的例外情况,如果前面的目录是符号链接,则允许使用循环目录引用。 例如,如果 any_directory 是符号链接 ,则允许上述示例中的数据文件路径 (仍然允许数据文件路径以' ../ ' 开头 。)

  • FILE_BLOCK_SIZE :此选项 - 特定于 InnoDB 常规表空间,并由 NDB -defines表空间数据文件的块大小 忽略 值可以以字节或千字节为单位指定。 例如,一个8千字节的文件块大小可以指定为8192或8K。 如果未指定此选项,则 FILE_BLOCK_SIZE 默认为该 innodb_page_size 值。 FILE_BLOCK_SIZE 当您打算使用表空间存储压缩 InnoDB 表( ROW_FORMAT=COMPRESSED 时,是必需的 在这种情况下,您必须 FILE_BLOCK_SIZE 在创建表 空间 定义表 空间。

    如果 FILE_BLOCK_SIZE 是相等的 innodb_page_size 值,则表可以含有具有未压缩的行格式仅表( COMPACT REDUNDANT ,和 DYNAMIC )。 具有 COMPRESSED 行格式的 表具有与 未压缩表不同的物理页大小。 因此,压缩表不能与未压缩表共存于同一表空间中。

    要使通用表空间包含压缩表, FILE_BLOCK_SIZE 必须指定该 FILE_BLOCK_SIZE ,并且该 值必须是 与该 值相关的有效压缩页大小 innodb_page_size 此外,压缩表( KEY_BLOCK_SIZE 的物理页面大小 必须等于 FILE_BLOCK_SIZE/1024 例如,如果 innodb_page_size=16K FILE_BLOCK_SIZE=8K ,该 KEY_BLOCK_SIZE 表必须为8欲了解更多信息,请参见 第15.6.3.3,“一般的表空间”

  • USE LOGFILE GROUP :必需 NDB ,这是以前使用创建的日志文件组的名称 CREATE LOGFILE GROUP 不支持 InnoDB ,失败并出错。

  • EXTENT_SIZE :此选项特定于NDB,并且InnoDB不支持该选项,因为它失败并出现错误。 EXTENT_SIZE 设置属于表空间的任何文件使用的范围的大小(以字节为单位)。 默认值为1M。 最小尺寸为32K,理论最大值为2G,但实际最大尺寸取决于许多因素。 在大多数情况下,更改范围大小对性能没有任何可测量的影响,建议除了最不寻常的情况之外的所有情况都使用默认值。

    程度 是磁盘空间分配的单位。 在使用另一个范围之前,一个范围充满了该范围可以包含的数据。 理论上,每个数据文件最多可使用65,535(64K)个扩展区; 但是,建议的最大值是32,768(32K)。 单个数据文件的建议最大大小为32G,即32K范围×每个范围1 MB。 此外,一旦将范围分配给给定分区,它就不能用于存储来自不同分区的数据; 范围无法存储来自多个分区的数据。 这意味着,例如,具有单个数据文件的表空间 INITIAL_SIZE (在下面的项目中描述)是256 MB并且其中 EXTENT_SIZE 128M只有两个扩展区,因此可用于存储来自最多两个不同磁盘数据表分区的数据。

    您可以通过查询 INFORMATION_SCHEMA.FILES 来查看给定数据文件中有多少个扩展区可用 ,因此可以估算文件中剩余的空间大小。 有关进一步的讨论和示例,请参见 第25.11节“INFORMATION_SCHEMA文件表”

  • INITIAL_SIZE :此选项特定于 失败并且出现错误的情况下 NDB 不受支持 InnoDB

    INITIAL_SIZE 参数设置特定使用的数据文件的总大小(以字节为单位) ADD DATATFILE 创建此文件后,其大小无法更改; 但是,您可以使用添加更多数据文件到表空间 ALTER TABLESPACE ... ADD DATAFILE

    INITIAL_SIZE 是可选的; 其默认值为134217728(128 MB)。

    在32位系统上,支持的最大值为 INITIAL_SIZE 4294967296(4 GB)。

  • AUTOEXTEND_SIZE :目前被MySQL忽略; 保留供将来使用。 无论使用何种存储引擎,在MySQL 8.0或MySQL NDB Cluster 8.0的任何版本中都不起作用。

  • MAX_SIZE :目前被MySQL忽略; 保留供将来使用。 无论使用何种存储引擎,在MySQL 8.0或MySQL NDB Cluster 8.0的任何版本中都不起作用。

  • NODEGROUP :目前被MySQL忽略; 保留供将来使用。 无论使用何种存储引擎,在MySQL 8.0或MySQL NDB Cluster 8.0的任何版本中都不起作用。

  • WAIT :目前被MySQL忽略; 保留供将来使用。 无论使用何种存储引擎,在MySQL 8.0或MySQL NDB Cluster 8.0的任何版本中都不起作用。

  • COMMENT :目前被MySQL忽略; 保留供将来使用。 无论使用何种存储引擎,在MySQL 8.0或MySQL NDB Cluster 8.0的任何版本中都不起作用。

  • ENCRYPTION 子句启用或禁用 InnoDB 常规表空间的 页级数据加密 MySQL 8.0.13中引入了对通用表空间的加密支持。

    从MySQL 8.0.16开始,如果 ENCRYPTION 未指定 子句,则该 default_table_encryption 设置控制是否启用加密。 ENCRYPTION 子句覆盖该 default_table_encryption 设置。 但是,如果 table_encryption_privilege_check 启用 变量, TABLE_ENCRYPTION_ADMIN 则需要使用与 ENCRYPTION 设置不同 子句设置 权限 default_table_encryption

    必须先安装和配置密钥环插件,然后才能创建启用加密的表空间。

    对通用表空间进行加密时,驻留在表空间中的所有表都将被加密。 同样,在加密表空间中创建的表也是加密的。

    有关更多信息,请参见 第15.6.3.9节“InnoDB静态数据加密”

  • ENGINE :定义使用表空间的存储引擎,其中 engine_name 是存储引擎的名称。 目前, InnoDB 标准MySQL 8.0版本 支持存储引擎。 MySQL NDB Cluster支持两者 NDB InnoDB 表空间。 如果未指定选项,则 default_storage_engine 使用系统变量 的值 ENGINE

笔记

  • 有关MySQL表空间命名的规则,请参见 第9.2节“模式对象名称” 除了这些规则之外, 不允许使用 斜杠字符( / ),也不能使用以?开头的名称 innodb_ ,因为此前缀保留供系统使用。

  • 不支持创建临时通用表空间。

  • 常规表空间不支持临时表。

  • TABLESPACE 选项可以与 表分区或子分区一起 使用 CREATE TABLE ALTER TABLE 分配给每个 InnoDB 表的文件表空间。 所有分区必须属于同一存储引擎。 InnoDB 不支持 将表分区分配给共享 表空间。 共享表空间包括 InnoDB 系统表空间和通用表空间。

  • 常规表空间支持使用任何行格式添加表 CREATE TABLE ... TABLESPACE innodb_file_per_table 不需要启用。

  • innodb_strict_mode 不适用于一般表空间。 表空间管理规则严格执行 innodb_strict_mode 如果 CREATE TABLESPACE 参数不正确或不兼容,则无论 innodb_strict_mode 设置 如何,操作都将失败 使用 CREATE TABLE ... TABLESPACE 将表添加到常规表空间时 ALTER TABLE ... TABLESPACE innodb_strict_mode 将忽略该 但会将该语句评估为 innodb_strict_mode 启用。

  • 使用 DROP TABLESPACE 删除表空间。 在删除表空间 DROP TABLE 之前, 必须从表空间 中删除所有表。 在删除NDB Cluster表空间之前,还必须使用一个或多个 ALTER TABLESPACE ... DROP DATATFILE 语句 删除其所有数据文件 请参见 第22.5.13.1节“NDB集群磁盘数据对象”

  • InnoDB 添加到 InnoDB 通用表空间 表的 所有部分 都驻留在通用表空间中,包括索引和 BLOB 页面。

    对于 NDB 分配给表空间的表,只有那些未编制索引的列存储在磁盘上,并实际使用表空间数据文件。 所有 NDB 表的 索引和索引列 始终保留在内存中。

  • 与系统表空间类似,截断或删除存储在通用表空间中的表会在通用表空间 .ibd数据文件 内部创建可用空间,该 文件 只能用于新 InnoDB 数据。 空间不会像文件每表表空间一样释放回操作系统。

  • 通用表空间不与任何数据库或模式关联。

  • ALTER TABLE ... DISCARD TABLESPACE 并且 ALTER TABLE ...IMPORT TABLESPACE 不支持属于常规表空间的表。

  • 服务器对引用常规表空间的DDL使用表空间级元数据锁定。 相比之下,服务器对引用每表文件表空间的DDL使用表级元数据锁定。

  • 生成的或现有的表空间不能更改为常规表空间。

  • 通用表空间名称和每个表文件表空间名称之间没有冲突。 一般表空间名称中不允许 使用 / 字符,该字符存在于每个表的表空间名称中。

  • mysqldump mysqlpump 不转储 InnoDB CREATE TABLESPACE 语句。

InnoDB示例

此示例演示如何创建常规表空间并添加三个不同行格式的未压缩表。

MySQL的> CREATE TABLESPACE `ts1` ADD DATAFILE 'ts1.ibd' ENGINE=INNODB;

MySQL的> CREATE TABLE t1 (c1 INT PRIMARY KEY) TABLESPACE ts1 ROW_FORMAT=REDUNDANT;

MySQL的> CREATE TABLE t2 (c1 INT PRIMARY KEY) TABLESPACE ts1 ROW_FORMAT=COMPACT;

MySQL的> CREATE TABLE t3 (c1 INT PRIMARY KEY) TABLESPACE ts1 ROW_FORMAT=DYNAMIC;

此示例演示如何创建常规表空间并添加压缩表。 该示例假定默认 innodb_page_size 值为16K。 FILE_BLOCK_SIZE 8192要求压缩表有 KEY_BLOCK_SIZE 8个。

MySQL的> CREATE TABLESPACE `ts2` ADD DATAFILE 'ts2.ibd' FILE_BLOCK_SIZE = 8192 Engine=InnoDB;

MySQL的> CREATE TABLE t4 (c1 INT PRIMARY KEY) TABLESPACE ts2 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;

此示例演示如何创建通用表空间而不指定 ADD DATAFILE 子句,从MySQL 8.0.14开始,该子句是可选的。

MySQL的> CREATE TABLESPACE `ts3` ENGINE=INNODB;

此示例演示如何创建撤消表空间。

MySQL的> CREATE UNDO TABLESPACE undo_003 ADD DATAFILE 'undo_003.ibu';

NDB示例

假设您希望创建一个 myts 使用 名为 的数据文件命名 的NDB Cluster Disk Data表空间 mydata-1.dat 一个 NDB 表空间总是需要使用由一个或多个撤消日志文件,日志文件组。 对于此示例,我们首先 使用 此处显示 语句 创建一个名为的日志文件组 mylg ,其中包含一个名为的undo long文件 myundo-1.dat CREATE LOGFILE GROUP

mysql> CREATE LOGFILE GROUP myg1
    - >      ADD UNDOFILE 'myundo-1.dat'
    - >     ENGINE=NDB;
查询OK,0行受影响(3.29秒)

现在,您可以使用以下语句创建先前描述的表空间:

mysql> CREATE TABLESPACE myts
    - >      ADD DATAFILE 'mydata-1.dat'
    - >      USE LOGFILE GROUP mylg
    - >     ENGINE=NDB;
查询OK,0行受影响(2.98秒)

您现在可以使用 CREATE TABLE 带有 TABLESPACE STORAGE DISK 选项 语句 创建磁盘数据表 ,类似于此处显示的内容:

mysql> CREATE TABLE mytable (
    - >      id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    - >      lname VARCHAR(50) NOT NULL,
    - >      fname VARCHAR(50) NOT NULL,
    - >      dob DATE NOT NULL,
    - >      joined DATE NOT NULL,
    - >      INDEX(last_name, first_name)
    - > )
    - >      TABLESPACE myts STORAGE DISK
    - >     ENGINE=NDB;
查询OK,0行受影响(1.41秒)

需要注意的是只有这一点非常重要 dob joined 列从 mytable 实际存储在磁盘上,由于事实 id lname fname 列所有索引。

如前所述,在 CREATE TABLESPACE 使用时 ENGINE [=] NDB ,会在每个NDB Cluster数据节点上创建表空间和关联的数据文件。 您可以通过查询 INFORMATION_SCHEMA.FILES 来验证数据文件是否已创建并获取有关它们的信息 ,如下所示:

mysql> SELECT FILE_NAME, FILE_TYPE, LOGFILE_GROUP_NAME, STATUS, EXTRA
    - >      FROM INFORMATION_SCHEMA.FILES
    - >     WHERE TABLESPACE_NAME = 'myts';

+ -------------- + ------------ + -------------------- + -------- + ---------------- +
| file_name | file_type | logfile_group_name | 状态| 额外的|
+ -------------- + ------------ + -------------------- + -------- + ---------------- +
| mydata-1.dat | DATAFILE | mylg | 正常| CLUSTER_NODE = 5 |
| mydata-1.dat | DATAFILE | mylg | 正常| CLUSTER_NODE = 6 |
| NULL | TABLESPACE | mylg | 正常| NULL |
+ -------------- + ------------ + -------------------- + -------- + ---------------- +
3行(0.01秒)

有关其他信息和示例,请参见 第22.5.13.1节“NDB集群磁盘数据对象”

13.1.22 CREATE TRIGGER语法

创建
    [DEFINER = user]
    TRIGGER 
    ON FOR EACH ROWtrigger_name
    trigger_time trigger_eventtbl_name
    [ trigger_order]
    trigger_body

trigger_time:{BEFORE | 之后}

trigger_event:{INSERT | 更新| 删除}

trigger_order:{跟进| PRECEDES}other_trigger_name

此语句创建一个新触发器。 触发器是与表关联的命名数据库对象,并在表发生特定事件时激活。 触发器与名为table的表相关联,该表 tbl_name 必须引用永久表。 您无法将触发器与 TEMPORARY 表或视图 相关联

模式名称空间中存在触发器名称,这意味着所有触发器必须在模式中具有唯一名称。 不同模式中的触发器可以具有相同的名称。

本节介绍 CREATE TRIGGER 语法。 有关其他讨论,请参见 第24.3.1节“触发器语法和示例”

CREATE TRIGGER 需要 TRIGGER 与触发器关联的表 权限。 如果该 DEFINER 子句存在,则所需的权限取决于 user 值,如 第24.6节“存储对象访问控制”中所述 如果启用了二进制日志记录,则 CREATE TRIGGER 可能需要该 SUPER 特权,如 第24.7节“存储程序二进制日志记录”中所述

DEFINER 子句确定在触发器激活时检查访问权限时要使用的安全上下文,如本节后面所述。

trigger_time 是触发动作时间。 它可以是 BEFORE AFTER 表示触发器在每行要修改之前或之后激活。

基本列值检查在触发器激活之前发生,因此您无法使用 BEFORE 触发器将不适合列类型的值转换为有效值。

trigger_event 表示激活触发器的操作类型。 trigger_event 允许 这些 值:

  • INSERT :只要在表中插入新行(例如,通过 ,和 语句) INSERT 触发器就会激活 LOAD DATA REPLACE

  • UPDATE :每当修改行时触发器都会激活(例如,通过 UPDATE 语句)。

  • DELETE :只要从表中删除行(例如,通过 DELETE REPLACE 语句) ,触发器就会激活 DROP TABLE 并且 TRUNCATE TABLE 表上的语句 不会 激活此触发器,因为它们不使用 DELETE 删除分区也不会激活 DELETE 触发器。

trigger_event 不代表激活触发器的文字类型的SQL语句,因为它表示一种表操作。 例如, INSERT 触发器不仅激活 INSERT 语句而且 激活 LOAD DATA 语句,因为两个语句都将行插入表中。

一个可能令人困惑的例子是 INSERT INTO ... ON DUPLICATE KEY UPDATE ... 语法: BEFORE INSERT 触发器为每一行激活,后跟 AFTER INSERT 触发器或两者 BEFORE UPDATE AFTER UPDATE 触发器,具体取决于行是否有重复的键。

注意

级联外键操作不会激活触发器。

可以为具有相同触发事件和操作时间的给定表定义多个触发器。 例如,您可以 BEFORE UPDATE 为表创建 两个 触发器。 默认情况下,具有相同触发事件和操作时间的触发器按创建顺序激活。 要影响触发器顺序,请指定一个 trigger_order 子句, 子句指示 FOLLOWS 或者 PRECEDES 具有相同触发事件和操作时间的现有触发器的名称。 使用时 FOLLOWS ,新触发器在现有触发器之后激活。 使用时 PRECEDES ,新触发器在现有触发器之前激活。

trigger_body 是触发器激活时要执行的语句。 要执行多个语句,请使用 BEGIN ... END 复合语句构造。 这也使您可以使用存储例程中允许的相同语句。 请参见 第13.6.1节“BEGIN ... END复合语句语法” 触发器中不允许使用某些语句; 请参见 第C.1节“存储程序的限制”

在触发器主体中,您可以使用别名 OLD 引用主题表(与触发器关联的表)中的列 NEW 在更新或删除之前,它指的是现有行的列。 指的是要插入的新行的列或更新后的现有行。 OLD.col_name NEW.col_name

触发器不能用于 或用于 引用生成的列。 有关生成的列的信息,请参见 第13.1.20.9节“创建表和生成的列” NEW.col_name OLD.col_name

MySQL sql_mode 在创建触发器时 存储有效的 系统变量设置,并始终使用此设置执行触发器主体, 而不管触发器开始执行时当前服务器SQL模式如何

DEFINER 子句指定在触发器激活时检查访问权限时要使用的MySQL帐户。 如果 DEFINER 子句,该 user 值应被指定为一个MySQL帐户 允许的 值取决于您拥有的权限,如 第24.6节“存储对象访问控制”中所述 有关触发器安全性的其他信息,另请参阅该部分。 'user_name'@'host_name' CURRENT_USER CURRENT_USER() user

如果 DEFINER 省略 子句,则默认定义者是执行该 CREATE TRIGGER 语句 的用户 这与 DEFINER = CURRENT_USER 明确 指定相同

DEFINER 在检查触发权限时, MySQL会将 用户考虑在内,如下所示:

  • CREATE TRIGGER 时间,谁发出语句的用户必须有 TRIGGER 特权。

  • 在触发器激活时,将针对 DEFINER 用户 检查权限 该用户必须具有以下权限:

    • TRIGGER 主题表 权限。

    • SELECT 如果使用 在触发器主体中 引用表列,则为主题表 特权 OLD.col_name NEW.col_name

    • UPDATE 如果表列是 触发器主体 赋值的 目标,则主题表 权限 SET NEW.col_name = value

    • 无论触发器执行的语句通常需要什么其他权限。

在触发器主体内,该 CURRENT_USER 函数返回用于在触发器激活时检查权限的帐户。 这是 DEFINER 用户,而不是其操作导致触发器被激活的用户。 有关触发器内用户审核的信息,请参见 第6.2.22节“基于SQL的帐户活动审核”

如果您使用 LOCK TABLES 锁定具有触发器的表,则触发器中使用的表也会被锁定,如 LOCK TABLES和Triggers中所述

有关触发器使用的其他讨论,请参见 第24.3.1节“触发器语法和示例”

13.1.23创建视图语法

创建
    [或更换]
    [ALGORITHM = {UNDEFINED | MERGE | 不是Temptable}]
    [DEFINER = user]
    [SQL SECURITY {DEFINER | INVOKER}]
    查看view_name[(column_list)]select_statement
    [WITH [CASCADED | 本地]检查选项]

CREATE VIEW 语句创建一个新视图,或者如果 OR REPLACE 给出 子句则 替换现有视图 如果视图不存在, CREATE OR REPLACE VIEW 则相同 CREATE VIEW 如果视图确实存在,则 CREATE OR REPLACE VIEW 替换它。

有关视图使用限制的信息,请参见 第C.5节“视图限制”

select_statement 是一个 SELECT 提供视图定义的语句。 (从视图中选择实际上是使用 SELECT 语句 select_statement 选择 。) 可以从基表或其他视图中进行选择。

视图定义 在创建时 冻结 ,不受后续表对基础表定义的更改的影响。 例如,如果视图定义为 SELECT * 在表上,则稍后添加到表中的新列不会成为视图的一部分,从表中删除的列将从视图中进行选择时导致错误。

ALGORITHM 子句影响MySQL处理视图的方式。 DEFINER SQL SECURITY 子句指定的安全上下文在查看调用时检查访问权限时使用。 WITH CHECK OPTION 子句可用于约束对视图引用的表中的行的插入或更新。 这些条款将在本节后面介绍。

CREATE VIEW 语句需要 CREATE VIEW 视图 特权,以及该 SELECT 语句 选择的每个列的一些特权 对于 SELECT 语句中 其他位置使用的列 ,您必须具有该 SELECT 权限。 如果该 OR REPLACE 子句存在,您还必须具有 DROP 该视图 权限。 如果该 DEFINER 子句存在,则所需的权限取决于 user 值,如 第24.6节“存储对象访问控制”中所述

引用视图时,将执行权限检查,如本节后面所述。

视图属于数据库。 默认情况下,在默认数据库中创建新视图。 要在给定数据库中显式创建视图,请使用 db_name.view_name 语法 使用 数据库名称限定视图名称:

CREATE VIEW test.v AS SELECT * FROM t;

SELECT 语句中的 非限定表或视图名称 也是针对默认数据库进行解释的。 视图可以通过使用适当的数据库名称限定表或视图名称来引用其他数据库中的表或视图。

在数据库中,基表和视图共享相同的命名空间,因此基表和视图不能具有相同的名称。

SELECT 语句 检索的列 可以是对表列的简单引用,也可以是使用函数,常量值,运算符等的表达式。

视图必须具有唯一的列名,没有重复项,就像基表一样。 默认情况下, SELECT 语句 检索的 列的名称将用于视图列名称。 要为视图列定义显式名称,请将可选 column_list 子句 指定 为逗号分隔标识符的列表。 名称的数量 column_list 必须与 SELECT 语句 检索的列数相同

可以从多种 SELECT 语句 创建视图 它可以引用基表或其他视图。 它可以使用连接 UNION 和子查询。 SELECT 甚至不需要引用任何表:

创建视图v_today(今天)AS SELECT CURRENT_DATE;

以下示例定义了一个视图,该视图从另一个表中选择两列以及从这些列计算的表达式:

mysql> CREATE TABLE t (qty INT, price INT);
mysql> INSERT INTO t VALUES(3, 50);
mysql> CREATE VIEW v AS SELECT qty, price, qty*price AS value FROM t;
mysql>SELECT * FROM v;
+ ------ + ------- ------- + +
| 数量| 价格| 价值|
+ ------ + ------- ------- + +
| 3 | 50 | 150 |
+ ------ + ------- ------- + +

视图定义受以下限制:

  • SELECT 语句不能引用系统变量或用户定义的变量。

  • 在存储的程序中, SELECT 语句不能引用程序参数或局部变量。

  • SELECT 语句不能引用预处理语句参数。

  • 定义中引用的任何表或视图都必须存在。 如果在创建视图后,删除了定义引用的表或视图,则使用该视图会导致错误。 要检查此类问题的视图定义,请使用该 CHECK TABLE 语句。

  • 该定义不能引用 TEMPORARY 表,也不能创建 TEMPORARY 视图。

  • 您无法将触发器与视图相关联。

  • SELECT 根据最大列长度64个字符(不是最大别名长度为256个字符)检查语句中 列名的 别名。

ORDER BY 在视图定义中是允许的,但如果使用具有自己的语句从视图中进行选择,则会忽略它 ORDER BY

对于定义中的其他选项或子句,它们将添加到引用视图的语句的选项或子句中,但效果未定义。 例如,如果视图定义包含 LIMIT 子句,并且您使用具有其自己的 LIMIT 子句 的语句从视图中进行选择 ,则未定义哪个限制适用。 这个道理同样适用于选项,例如 ALL DISTINCT 或者 SQL_SMALL_RESULT 后面的 SELECT 关键字,并以条款,例如 INTO FOR UPDATE FOR SHARE LOCK IN SHARE MODE ,和 PROCEDURE

如果通过更改系统变量更改查询处理环境,则视图中获得的结果可能会受到影响:

MySQL的> CREATE VIEW v (mycol) AS SELECT 'abc';
查询OK,0行受影响(0.01秒)

MySQL的> SET sql_mode = '';
查询正常,0行受影响(0.00秒)

MySQL的> SELECT "mycol" FROM v;
+ ------- +
| mycol |
+ ------- +
| mycol |
+ ------- +
1排(0.01秒)

MySQL的> SET sql_mode = 'ANSI_QUOTES';
查询正常,0行受影响(0.00秒)

MySQL的> SELECT "mycol" FROM v;
+ ------- +
| mycol |
+ ------- +
| abc |
+ ------- +
1排(0.00秒)

DEFINER SQL SECURITY 条款确定哪个MySQL账户时,执行语句引用视图的视图检查访问权限时使用。 有效的 SQL SECURITY 特征值是 DEFINER (默认值)和 INVOKER 这些表明必须由分别定义或调用视图的用户持有所需的权限。

如果 DEFINER 子句,该 user 值应被指定为一个MySQL帐户 允许的 值取决于您拥有的权限,如 第24.6节“存储对象访问控制”中所述 有关视图安全性的其他信息,另请参阅该部分。 'user_name'@'host_name' CURRENT_USER CURRENT_USER() user

如果 DEFINER 省略 子句,则默认定义者是执行该 CREATE VIEW 语句 的用户 这与 DEFINER = CURRENT_USER 明确 指定相同

在视图定义中,该 CURRENT_USER 函数 DEFINER 默认 返回视图的 值。 对于使用 SQL SECURITY INVOKER 特征 定义 CURRENT_USER 的视图 返回视图调用者的帐户。 有关视图中的用户审核的信息,请参见 第6.2.22节“基于SQL的帐户活动审核”

在使用 SQL SECURITY DEFINER 特性 定义的存储例程中 CURRENT_USER 返回例程的 DEFINER 值。 如果视图定义包含 DEFINER ,则这也会影响在此例程中定义的视图 CURRENT_USER

MySQL检查查看权限,如下所示:

  • 在视图定义时,视图创建者必须具有使用视图访问的顶级对象所需的权限。 例如,如果视图定义引用表列,则创建者必须对定义的选择列表中的每个列具有一些特权,并且 SELECT 对定义中其他位置使用的每个列 具有 特权。 如果定义引用存储的函数,则只能检查调用该函数所需的权限。 函数调用时所需的权限只能在执行时检查:对于不同的调用,可能会采用函数内的不同执行路径。

  • 引用视图的用户必须具有访问它的适当权限( SELECT 从中进行选择, INSERT 插入 视图 等)。

  • 引用视图时 DEFINER ,将根据 视图 帐户或调用者所 拥有的权限检查视图访问的对象的权限 ,具体取决于 SQL SECURITY 特征 是否 DEFINER INVOKER

  • 如果对视图的引用导致执行存储的函数,则对函数内执行的语句的特权检查取决于函数 SQL SECURITY 特征 是否 DEFINER INVOKER 如果安全特性是 DEFINER ,则该功能以 DEFINER 帐户 的权限运行 如果特征是 INVOKER ,则该函数以视图 SQL SECURITY 特征 确定的特权运行

示例:视图可能依赖于存储的函数,该函数可能会调用其他存储的例程。 例如,以下视图调用存储的函数 f()

创建视图v SELECT SELECT * FROM t WHERE t.id = f(t.name);

假设 f() 包含如下语句:

如果名称IS为NULL
  CALL p1();
其他
  CALL p2();
万一;

执行时 f() 需要检查 执行语句所需的权限 f() 这可能意味着需要特权, p1() 或者 p2() 取决于其中的执行路径 f() 必须在运行时检查这些权限,并且必须拥有权限的用户由 SQL SECURITY 视图 v 和函数 确定 f()

视图 DEFINER SQL SECURITY 子句是标准SQL的扩展。 在标准SQL中,使用规则处理视图 SQL SECURITY DEFINER 该标准表示视图的定义者(与视图模式的所有者相同)在视图上获得适用的权限(例如, SELECT )并且可以授予它们。 MySQL没有架构 所有者 ”的 概念 ,因此MySQL添加了一个子句来识别定义器。 DEFINER 条款是一个扩展,其目的是具有标准所具有的内容; 也就是说,谁定义了视图的永久记录。 这就是默认 DEFINER 值是视图创建者的帐户的原因。

optional ALGORITHM 子句是标准SQL的MySQL扩展。 它会影响MySQL处理视图的方式。 ALGORITHM 三个值: MERGE TEMPTABLE UNDEFINED 有关更多信息,请参见 第24.5.2节“视图处理算法” ,以及 第8.2.2.4节“使用合并或实现优化派生表,视图引用和公用表表达式”

有些视图是可更新的。 也就是说,你可以在语句,如使用它们 UPDATE DELETE INSERT 更新基础表的内容。 要使视图可更新,视图中的行与基础表中的行之间必须存在一对一的关系。 还有一些其他构造使视图不可更新。

视图中生成的列被视为可更新,因为可以为其分配。 但是,如果明确更新此类列,则唯一允许的值为 DEFAULT 有关生成的列的信息,请参见 第13.1.20.9节“创建表和生成的列”

WITH CHECK OPTION 可以为可更新视图提供 子句,以防止对行的插入或更新,除了其中的 WHERE 子句 select_statement 为true的行。

WITH CHECK OPTION 可更新视图 子句中, LOCAL CASCADED 关键字确定在根据另一个视图定义视图时检查测试的范围。 LOCAL 关键字限制 CHECK OPTION 只向视图限定。 CASCADED 还会导致对基础视图的检查进行评估。 如果没有给出关键字,则默认为 CASCADED

有关可更新视图和 WITH CHECK OPTION 子句的 更多信息 ,请参见 第24.5.3节“可更新和可插入视图” 第24.5.4节“视图WITH CHECK OPTION子句”

13.1.24 DROP DATABASE语法

DROP {DATABASE | SCHEMA} [如果存在]db_name

DROP DATABASE 删除数据库中的所有表并删除数据库。 对此声明 非常 小心! 要使用 DROP DATABASE ,您需要 DROP 数据库 权限。 DROP SCHEMA 是...的同义词 DROP DATABASE

重要

删除数据库时, 不会 自动删除 专门为数据库授予的权限 必须手动删除它们。 请参见 第13.7.1.6节“GRANT语法”

IF EXISTS 用于防止在数据库不存在时发生错误。

如果删除默认数据库,则取消设置默认数据库( DATABASE() 函数返回 NULL )。

如果 DROP DATABASE 在符号链接的数据库上使用,则链接和原始数据库都将被删除。

DROP DATABASE 返回已删除的表的数量。

DROP DATABASE 语句从给定的数据库目录中删除MySQL本身在正常操作期间可能创建的文件和目录。 这包括具有以下列表中显示的扩展名的所有文件:

  • .BAK

  • .DAT

  • .HSH

  • .MRG

  • .MYD

  • .MYI

  • .cfg

  • .db

  • .ibd

  • .ndb

如果在MySQL删除刚刚列出的文件或目录后,其他文件或目录仍保留在数据库目录中,则无法删除数据库目录。 在这种情况下,您必须手动删除任何剩余的文件或目录并 DROP DATABASE 再次 发出该 语句。

删除数据库不会删除 TEMPORARY 在该数据库中创建的 任何 表。 TEMPORARY 当创建它们的会话结束时,会自动删除这些表。 请参见 第13.1.20.3节“CREATE TEMPORARY TABLE语法”

您也可以使用 mysqladmin 删除数据库 请参见 第4.5.2节“ mysqladmin - 管理MySQL服务器的客户端”

13.1.25 DROP EVENT语法

DROP EVENT [如果存在] event_name

此语句将删除名为的事件 event_name 该事件立即停止活动,并从服务器中完全删除。

如果事件不存在, 则会 出现错误 ERROR 1517(HY000):未知事件' event_name ' 您可以覆盖它并使该语句为不存在的事件生成警告,而不是使用 IF EXISTS

此语句需要 EVENT 要删除事件所属的架构 权限。

13.1.26 DROP FUNCTION语法

DROP FUNCTION 语句用于删除存储的函数和用户定义的函数(UDF):

13.1.27 DROP INDEX语法

DROP INDEX index_nameON tbl_name
    [ algorithm_option| lock_option] ......

algorithm_option
    算法[=] {DEFAULT | INPLACE | COPY}

lock_option
    LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE}

DROP INDEX 删除 index_name 从表中 命名的索引 tbl_name 此语句映射 ALTER TABLE 到删除索引 语句。 请参见 第13.1.9节“ALTER TABLE语法”

要删除主键,索引名称始终 PRIMARY 为必须指定为带引号的标识符,因为 PRIMARY 它是保留字:

DROP INDEX`PRIMARY`ON;

NDB 表格的 可变宽度列的索引 在线删除; 也就是说,没有任何表复制。 该表未被锁定以防止来自其他NDB Cluster API节点的访问,尽管在操作期间它被锁定在 同一 API节点 上的其他 操作。 这是由服务器在确定可以这样做时自动完成的; 您不必使用任何特殊的SQL语法或服务器选项来导致它发生。

ALGORITHM 并且 LOCK 可以赋予子句以影响表复制方法和在修改索引时读写表的并发级别。 它们与 ALTER TABLE 声明 具有相同的含义 有关更多信息,请参见 第13.1.9节“ALTER TABLE语法”

MySQL NDB Cluster使用 ALGORITHM=INPLACE 标准MySQL服务器支持 的相同 语法 支持在线操作 有关 更多信息 请参见 第22.5.14节“使用NDB簇中的ALTER TABLE进行联机操作”

13.1.28 DROP LOGFILE GROUP语法

DROP LOGFILE GROUP logfile_group
    ENGINE [=]engine_name

此语句删除名为的日志文件组 logfile_group 日志文件组必须已存在或导致错误。 (有关创建日志文件组的信息,请参见 第13.1.16节“CREATE LOGFILE GROUP语法” 。)

重要

在删除日志文件组之前,必须删除使用该日志文件组进行 UNDO 日志记录的 所有表空间

required ENGINE 子句提供要删除的日志文件组使用的存储引擎的名称。 目前,唯一允许的值 engine_name NDB NDBCLUSTER

DROP LOGFILE GROUP 仅适用于NDB Cluster的磁盘数据存储。 请参见 第22.5.13节“NDB集群磁盘数据表”

13.1.29 DROP PROCEDURE和DROP FUNCTION语法

DROP {PROCEDURE | 功能} [如果存在]sp_name

此语句用于删除存储过程或函数。 也就是说,从服务器中删除指定的例程。 你必须拥有 ALTER ROUTINE 例行公事 特权。 (如果 automatic_sp_privileges 启用 系统变量, EXECUTE 则在创建例程时将该 特权 自动授予例程创建者,并在例程被删除时从创建者中删除该 特权 。请参见 第24.2.2节“存储的例程和MySQL特权” 。)

IF EXISTS 子句是MySQL扩展。 如果过程或函数不存在,它可以防止发生错误。 生成可以查看的警告 SHOW WARNINGS

DROP FUNCTION 也用于删除用户定义的函数(请参见 第13.7.4.2节“DROP FUNCTION语法” )。

13.1.30 DROP SERVER语法

DROP SERVER [如果存在] server_name

删除名为的服务器的服务器定义 server_name mysql.servers 表中 的相应行将 被删除。 此声明需要该 SUPER 权限。

删除表的服务器不会影响 FEDERATED 在创建表时使用此连接信息的 任何 表。 请参见 第13.1.18节“创建服务器语法”

DROP SERVER 导致隐式提交。 请参见 第13.3.3节“导致隐式提交的语句”

DROP SERVER 无论正在使用的日志记录格式如何,都不会写入二进制日志。

13.1.31 DROP空间参考系统语法

DROP空间参考系统
    [如果存在]
    srid

srid32-bit unsigned integer

此语句 从数据字典中 删除 空间参照系 (SRS)定义。 它需要 SUPER 特权。

例:

DROP空间参考系统4120;

如果不存在具有SRID值的SRS定义,则除非 IF EXISTS 指定 ,否则 发生错误 在这种情况下,会发出警告而不是错误。

如果现有表中的某些列使用SRID值,则会发生错误。 例如:

MySQL的> DROP SPATIAL REFERENCE SYSTEM 4326;
ERROR 3716(SR005):无法修改SRID 4326。有
至少有一列取决于它。

要标识哪个或哪些列使用SRID,请使用以下查询:

SELECT * FROM INFORMATION_SCHEMA.ST_GEOMETRY_COLUMNS WHERE SRS_ID = 4326;

SRID值必须在32位无符号整数的范围内,具有以下限制:

  • SRID 0是有效的SRID,但不能与之一起使用 DROP SPATIAL REFERENCE SYSTEM

  • 如果该值在保留的SRID范围内,则会发出警告。 保留范围为[0,32767](由EPSG保留),[60,000,000,69,999,999](由EPSG保留)和[2,000,000,000,2,147,483,647](由MySQL保留)。 EPSG代表 欧洲石油调查组

  • 用户不应丢弃具有保留范围中的SRID的SRS。 如果删除了系统安装的SRS,则可以为MySQL升级重新创建SRS定义。

13.1.32 DROP TABLE语法

DROP [TEMPORARY] TABLE [IF EXISTS]
     tbl_name[,tbl_name] ......
    [限制| 级联]

DROP TABLE 删除一个或多个表。 您必须拥有 DROP 每个表 权限。

小心 这个说法! 对于每个表,它将删除表定义和所有表数据。 如果表已分区,则该语句将删除表定义,其所有分区,存储在这些分区中的所有数据以及与已删除表关联的所有分区定义。

删除表也会删除表的任何触发器。

DROP TABLE 导致隐式提交,除非与 TEMPORARY 关键字一起使用。 请参见 第13.3.3节“导致隐式提交的语句”

重要

删除表时, 不会 自动删除 专门为该表授予的权限 必须手动删除它们。 请参见 第13.7.1.6节“GRANT语法”

如果参数列表中指定的任何表不存在,则 DROP TABLE 行为取决于是否 IF EXISTS 给出 了该 子句:

  • 如果没有 IF EXISTS ,则语句失败并显示错误,指示无法删除哪些不存在的表,并且不进行任何更改。

  • 使用 IF EXISTS 时,不存在的表不会发生错误。 该语句将删除所有存在的命名表,并 NOTE 为每个不存在的表 生成 诊断。 这些注释可以显示 SHOW WARNINGS 请参见 第13.7.6.40节“显示警告语法”

IF EXISTS 对于在特殊情况下删除表也很有用,在这种情况下,数据字典中有条目但没有存储引擎管理的表。 (例如,如果在从存储引擎中删除表之后但在删除数据字典条目之前发生异常服务器退出。)

TEMPORARY 关键字具有以下效果:

  • 该声明仅删除 TEMPORARY 表格。

  • 该语句不会导致隐式提交。

  • 没有检查访问权限。 一个 TEMPORARY 表可见只与创建它的会话,所以没有检查是必要的。

包含 TEMPORARY 关键字是防止意外丢弃非 TEMPORARY 的好方法

RESTRICT CASCADE 关键字无能为力。 允许它们从其他数据库系统中轻松移植。

DROP TABLE 并非所有 innodb_force_recovery 设置 都支持 请参见 第15.20.2节“强制InnoDB恢复”

13.1.33 DROP TABLESPACE语法

DROP [UNDO] TABLESPACE tablespace_name
    [ENGINE [=] engine_name]

此语句删除以前使用创建的表空间 CREATE TABLESPACE 它是由支持 NDB InnoDB 存储引擎。

UNDO 必须指定在MySQL 8.0.14中引入 关键字以删除撤消表空间。 只能 CREATE UNDO TABLESPACE 删除 使用 语法 创建的撤消表空间 撤消表空间必须处于 empty 可以删除之前 状态。 有关更多信息,请参见 第15.6.3.4节“撤消表空间”

ENGINE 设置使用表空间的存储引擎,其中 engine_name 是存储引擎的名称。 目前,值 InnoDB NDB 支持。 如果未设置, default_storage_engine 则使用 如果它与用于创建表空间的存储引擎不同,则该 DROP TABLESPACE 语句将失败。

tablespace_name 是MySQL中区分大小写的标识符。

对于 InnoDB 通用表空间,必须在 DROP TABLESPACE 操作 之前从表空间中删除所有表 如果表空间不为空,则 DROP TABLESPACE 返回错误。

NDB 要删除 表空间不得包含任何数据文件; 换句话说,在删除 NDB 表空间之前,必须先使用删除每个数据文件 ALTER TABLESPACE ... DROP DATAFILE

笔记

  • InnoDB 删除表空间中的最后一个表时,不会自动删除 常规 表空间。 必须使用显式删除表空间 DROP TABLESPACE tablespace_name

  • 一个 DROP DATABASE 操作可以丢弃属于一般的表空间的表,但它不能删除表空间,即使操作下降属于表空间中的所有表。 必须使用显式删除表空间 DROP TABLESPACE tablespace_name

  • 与系统表空间类似,截断或删除存储在通用表空间中的表会在通用表空间 .ibd数据文件 内部创建可用空间,该 文件 只能用于新 InnoDB 数据。 空间不会像文件每表表空间一样释放回操作系统。

InnoDB示例

此示例演示如何删除 InnoDB 常规表空间。 ts1 使用单个表创建 常规表空间 在删除表空间之前,必须删除该表。

MySQL的> CREATE TABLESPACE `ts1` ADD DATAFILE 'ts1.ibd' Engine=InnoDB;     

MySQL的> CREATE TABLE t1 (c1 INT PRIMARY KEY) TABLESPACE ts10 Engine=InnoDB;     

MySQL的> DROP TABLE t1;

MySQL的> DROP TABLESPACE ts1;

此示例演示了删除撤消表空间。 撤消表空间必须处于 empty 可以删除之前 状态。 有关更多信息,请参见 第15.6.3.4节“撤消表空间”

MySQL的> DROP UNDO TABLESPACE undo_003;

NDB示例

这个例子展示了如何删除一个 NDB myts 具有命名的数据文件 mydata-1.dat 之后首先创建表,并假定命名一个日志文件组的存在 mylg (见 章节13.1.16,“CREATE LOGFILE GROUP语法” )。

mysql> CREATE TABLESPACE myts
    - >      ADD DATAFILE 'mydata-1.dat'
    - >      USE LOGFILE GROUP mylg
    - >     ENGINE=NDB;

ALTER TABLESPACE 如下所示, 必须先删除表空间中的所有数据文件 ,然后才能删除它们:

mysql> ALTER TABLESPACE myts
    - >      DROP DATAFILE 'mydata-1.dat'
    - >     ENGINE=NDB;

MySQL的> DROP TABLESPACE myts;

13.1.34 DROP TRIGGER语法

DROP TRIGGER [IF EXISTS] [ schema_name。]trigger_name

此语句删除触发器。 模式(数据库)名称是可选的。 如果省略了架构,则会从默认架构中删除触发器。 DROP TRIGGER 需要 TRIGGER 与触发器关联的表 权限。

使用 IF EXISTS 以防止发生错误,从一个不存在的触发器发生。 NOTE 使用时不存在的触发产生 IF EXISTS 请参见 第13.7.6.40节“显示警告语法”

如果删除表,也会删除表的触发器。

13.1.35 DROP VIEW语法

DROP VIEW [IF EXISTS]
     view_name[,view_name] ......
    [限制| 级联]

DROP VIEW 删除一个或多个视图。 您必须拥有 DROP 每个视图 权限。

如果参数列表中指定的任何视图不存在,则该语句将失败,并显示一个错误,该错误按名称指示它无法删除的不存在的视图,并且不进行任何更改。

注意

在MySQL 5.7及更早版本中, DROP VIEW 如果参数列表中指定的任何视图不存在,则返回错误,但也会丢弃列表中存在的所有视图。 由于MySQL 8.0中的行为发生了变化, DROP VIEW MySQL 5.7主服务器上的 部分完成 操作在MySQL 8.0从服务器上复制时失败。 要避免此故障情形,请 IF EXISTS DROP VIEW 语句中 使用 语法 以防止对不存在的视图发生错误。 有关更多信息,请参见 第13.1.1节“原子数据定义语句支持”

IF EXISTS 子句可防止对不存在的视图发生错误。 给出此子句时, NOTE 将为每个不存在的视图生成 a 请参见 第13.7.6.40节“显示警告语法”

RESTRICT 并且 CASCADE ,如果给定,则被解析并被忽略。

13.1.36 RENAME TABLE语法

RENAME TABLE
     tbl_nameTO new_tbl_name
    [,tbl_name2TO new_tbl_name2] ......

RENAME TABLE 重命名一个或多个表。 您必须具有 ALTER DROP 原始表的权限,以及 CREATE INSERT 新表的权限。

例如,重命名一个指定的表 old_table new_table ,用这个语句:

RENAME TABLE old_table TO new_table;

该声明等同于以下 ALTER TABLE 声明:

ALTER TABLE old_table RENAME new_table;

RENAME TABLE 与之不同 ALTER TABLE ,可以在一个语句中重命名多个表:

RENAME TABLE old_table1到new_table1,
             old_table2到new_table2,
             old_table3 TO new_table3;

重命名操作从左到右执行。 因此,要交换两个表名,请执行此操作(假设具有中间名称的表 tmp_table 尚不存在):

RENAME TABLE old_table TO tmp_table,
             new_table TO old_table,
             tmp_table TO new_table;

表上的元数据锁是按名称顺序获取的,在某些情况下,当多个事务并发执行时,这会对操作结果产生影响。 请参见 第8.11.4节“元数据锁定”

从MySQL 8.0.13开始,您可以重命名用 LOCK TABLES 语句 锁定的 表,前提是它们是使用锁定锁定的, WRITE 或者是 WRITE 多表重命名操作中前面步骤中 重命名 锁定表 的产物 例如,允许这样做:

LOCK TABLE old_table1 WRITE;
RENAME TABLE old_table1到new_table1,
             new_table1 TO new_table2;

这是不允许的:

LOCK TABLE old_table1 READ;
RENAME TABLE old_table1到new_table1,
             new_table1 TO new_table2;

在MySQL 8.0.13之前,要执行 RENAME TABLE ,必须没有锁定表 LOCK TABLES

在满足事务表锁定条件的情况下,重命名操作以原子方式完成; 在重命名正在进行时,没有其他会话可以访问任何表。

如果在a期间发生任何错误 RENAME TABLE ,则语句将失败并且不会进行任何更改。

您可以使用 RENAME TABLE 将表从一个数据库移动到另一个数据库:

重命名表current_db.tbl_nameTOother_db.tbl_name;

使用此方法将所有表从一个数据库移动到另一个数据库实际上重命名数据库(MySQL没有单个语句的操作),除了原始数据库继续存在,尽管没有表。

喜欢 RENAME TABLE ALTER TABLE ... RENAME 也可以用来将表移动到不同的数据库。 无论使用何种语句,如果重命名操作将表移动到位于不同文件系统上的数据库,则结果的成功是特定于平台的,并且取决于用于移动表文件的基础操作系统调用。

如果表具有触发器,则尝试将表重命名为其他数据库会 因错误的schema ER_TRG_IN_WRONG_SCHEMA )错误 触发器而 失败

未加密的表可以移动到启用加密的数据库,反之亦然。 但是,如果 table_encryption_privilege_check 启用了 变量, TABLE_ENCRYPTION_ADMIN 则如果表加密设置与默认数据库加密不同,则需要 权限。

要重命名 TEMPORARY 表, RENAME TABLE 不起作用。 ALTER TABLE 改用。

RENAME TABLE 适用于视图,但视图无法重命名为其他数据库。

专门为重命名的表或视图授予的任何权限都不会迁移到新名称。 必须手动更改它们。

RENAME TABLE tbl_name TO new_tbl_name 更改内部生成的外键约束名称和以字符串 tbl_name _ibfk_ 开头 以反映新表名称的 用户定义的外键约束名称 InnoDB 将以字符串 tbl_name _ibfk_ 开头的外键约束名称解释 为内部生成的名称。

除非存在冲突,否则指向重命名表的外键约束名称将自动更新,在这种情况下,语句将失败并显示错误。 如果重命名的约束名称已存在,则会发生冲突。 在这种情况下,您必须删除并重新创建外键才能使其正常运行。

RENAME TABLE tbl_name TO new_tbl_name 更改内部生成的和用户定义的 CHECK 约束名称,以字符串 tbl_name _chk_ 开头 以反映新的表名。 MySQL CHECK 将以字符串 tbl_name _chk_ 开头的约束名称 解释 为内部生成的名称。 例:

MySQL的> SHOW CREATE TABLE t1\G
*************************** 1。排******************** *******
       表:t1
创建表:CREATE TABLE`t1`(
  `i1` int(11)DEFAULT NULL,
  `i2` int(11)DEFAULT NULL,
  约束`t1_chk_1`检查((``i1`> 0)),
  约束`t1_chk_2`检查((``i2` <0))
)ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci
1排(0.02秒)

MySQL的> RENAME TABLE t1 TO t3;
查询正常,0行受影响(0.03秒)

MySQL的> SHOW CREATE TABLE t3\G
*************************** 1。排******************** *******
       表:t3
创建表:CREATE TABLE`t3`(
  `i1` int(11)DEFAULT NULL,
  `i2` int(11)DEFAULT NULL,
  约束`t3_chk_1`检查((``i1`> 0)),
  约束`t3_chk_2`检查((``i2` <0))
)ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci
1排(0.01秒)

13.1.37 TRUNCATE TABLE语法

TRUNCATE [表] tbl_name

TRUNCATE TABLE 完全清空一张桌子。 它需要 DROP 特权。 从逻辑上讲, TRUNCATE TABLE 类似于一个 DELETE 一个删除所有行,或序列声明 DROP TABLE CREATE TABLE 陈述。

要实现高性能,请 TRUNCATE TABLE 绕过删除数据的DML方法。 因此,它不会导致 ON DELETE 触发器触发,它不能对 InnoDB 具有父子外键关系的表 执行 ,并且不能像DML操作那样回滚。 但是, TRUNCATE TABLE 如果服务器在运行期间暂停,则对使用原子DDL支持的存储引擎的表的操作要么完全提交,要么回滚。 有关更多信息,请参见 第13.1.1节“原子数据定义语句支持”

虽然 TRUNCATE TABLE 类似 DELETE ,但它被归类为DDL语句而不是DML语句。 它与 DELETE 以下方式不同:

  • 截断操作会删除并重新创建表,这比逐个删除行要快得多,特别是对于大型表。

  • 截断操作会导致隐式提交,因此无法回滚。 请参见 第13.3.3节“导致隐式提交的语句”

  • 如果会话持有活动表锁,则无法执行截断操作。

  • TRUNCATE TABLE 如果 引用该表的其他表 有任何 约束, InnoDB 表或 NDB 失败 FOREIGN KEY 允许同一表的列之间的外键约束。

  • 截断操作不会为已删除的行数返回有意义的值。 通常的结果是 0行受影响 ,应该被解释为 没有信息。

  • 只要表定义有效, TRUNCATE TABLE 即使数据或索引文件已损坏,也 可以将表重新创建为空表

  • 任何 AUTO_INCREMENT 值都将重置为其起始值。 即使对于 MyISAM 并且 InnoDB 通常不重用序列值也是如此。

  • 与分区表一起使用时, TRUNCATE TABLE 保留分区; 也就是说,数据和索引文件被删除并重新创建,而分区定义不受影响。

  • TRUNCATE TABLE 语句不会调用 ON DELETE 触发器。

  • InnoDB 支持 截断损坏的 表。

TRUNCATE TABLE 对于表关闭所有打开的表的处理程序 HANDLER OPEN

TRUNCATE TABLE 被处理用于二进制日志记录和复制的目的, DROP TABLE 后面是 CREATE TABLE -dhat,而不是DML。 这是因为,当使用 InnoDB 事务隔离级别不允许基于语句的日志记录( READ COMMITTED READ UNCOMMITTED )的 事务存储引擎 时,使用 STATEMENT MIXED 记录模式 时不会记录和复制该语句 (缺陷号36763)但是,它仍然 InnoDB 以前面描述的方式 应用于复制从属设备

在MySQL 5.7及更早版本中,在具有大缓冲池并 innodb_adaptive_hash_index 启用的 TRUNCATE TABLE 系统上,由于在删除表的自适应哈希索引条目时发生LRU扫描,操作可能导致系统性能暂时下降(Bug#68184)。 重新映射 TRUNCATE TABLE MySQL 8.0 DROP TABLE CREATE TABLE 在MySQL 8.0中避免了有问题的LRU扫描。

TRUNCATE TABLE 可以与性能架构摘要表一起使用,但效果是将摘要列重置为0,或者 NULL 不删除行。 请参见 第26.12.16节“性能模式摘要表”

13.2数据处理语句

13.2.1 CALL语法

CALL sp_name([ parameter[,...]])
CALL sp_name[()]

CALL 语句调用先前定义的存储过程 CREATE PROCEDURE

不带括号的存储过程可以在没有括号的情况下调用。 也就是说, CALL p() 而且 CALL p 是等价的。

CALL 可以使用声明为 OUT INOUT 参数的 参数将值传回给调用者 当过程返回时,客户端程序还可以获取在例程中执行的最终语句受影响的行数:在SQL级别,调用该 ROW_COUNT() 函数; 从C API,调用该 mysql_affected_rows() 函数。

有关未处理条件对过程参数的影响的信息,请参见 第13.6.7.8节“条件处理和OUT或INOUT参数”

要使用 OUT or INOUT 参数 从过程中获取值 ,请通过用户变量传递参数,然后在过程返回后检查变量的值。 (如果要调用从另一个存储过程或函数内的程序,也可以通过常规参数或局部例程变量作为 IN INOUT 参数)。对于一个 INOUT 参数,它传递给过程之前初始化它的值。 以下过程具有 OUT 过程设置为当前服务器版本的 INOUT 参数,以及过程从其当前值开始递增的值:

CREATE PROCEDURE p(OUT ver_param VARCHAR(25),INOUT incr_param INT)
开始
  #设置OUT参数的值
  SELECT VERSION()INTO ver_param;
  #INOUT参数的增量值
  SET incr_param = incr_param + 1;
结束;

在调用该过程之前,初始化要作为 INOUT 参数 传递的变量 调用该过程后,将设置或修改两个变量的值:

mysql> SET @increment = 10;
mysql> CALL p(@version, @increment);
mysql>SELECT @version, @increment;
+ -------------------- + ------------ +
| @version | @increment |
+ -------------------- + ------------ +
| 8.0.3-rc-debug-log | 11 |
+ -------------------- + ------------ +

CALL 使用 PREPARE 和的 EXECUTE 准备 语句中 ,占位符可用于 IN 参数 OUT INOUT 参数。 这些类型的参数可以使用如下:

mysql> SET @increment = 10;
mysql> PREPARE s FROM 'CALL p(?, ?)';
mysql> EXECUTE s USING @version, @increment;
mysql>SELECT @version, @increment;
+ -------------------- + ------------ +
| @version | @increment |
+ -------------------- + ------------ +
| 8.0.3-rc-debug-log | 11 |
+ -------------------- + ------------ +

要编写使用 CALL SQL语句执行生成结果集的存储过程的 C程序, CLIENT_MULTI_RESULTS 必须启用 标志。 这是因为 CALL 除了过程中执行的语句可能返回的任何结果集之外, 每个都 返回一个结果来指示调用状态。 CLIENT_MULTI_RESULTS 如果 CALL 用于执行包含预准备语句的任何存储过程, 则还必须启用 无论何时加载这样的过程都无法确定这些语句是否会产生结果集,因此有必要假设它们会产生结果集。

CLIENT_MULTI_RESULTS 可以在调用时启用 mysql_real_connect() ,可以通过传递 CLIENT_MULTI_RESULTS 标志本身 显式 启用 ,也可以通过传递 隐式 CLIENT_MULTI_STATEMENTS 启用(也可以启用 CLIENT_MULTI_RESULTS )。 CLIENT_MULTI_RESULTS 默认情况下启用。

要处理 CALL 使用 mysql_query() or 执行 语句 的结果 mysql_real_query() ,请使用调用的循环 mysql_next_result() 来确定是否有更多结果。 有关示例,请参见 第28.7.23节“C API多语句执行支持”

C程序可以使用prepared-statement接口来执行 CALL 语句,访问 OUT INOUT 参数。 这是通过 CALL 使用循环 处理 语句 的结果来完成的,该 循环调用 mysql_stmt_next_result() 以确定是否有更多结果。 有关示例,请参见 第28.7.25节“C API准备的CALL语句支持” 提供MySQL接口的语言可以使用预准备 CALL 语句直接检索 OUT INOUT 过程参数。

检测到存储程序引用的对象的元数据更改,并在下次执行程序时自动重新分析受影响的语句。 有关更多信息,请参见 第8.10.3节“准备语句和存储程序的缓存”

13.2.2 DELETE语法

DELETE 是一个从表中删除行的DML语句。

一个 DELETE 语句可以用开始 WITH 子句来定义内访问的公共表表达式 DELETE 请参见 第13.2.13节“WITH语法(公用表表达式)”

单表语法

tbl_name[[AS] tbl_alias] 删除[LOW_PRIORITY] [QUICK] [IGNORE ]
    [PARTITION(partition_name[,partition_name] ...)]
    [在哪里where_condition]
    [订购...]
    [限制row_count]

DELETE 语句从中删除行 tbl_name 并返回已删除行的数量。 要检查已删除行的数量,请调用 第12.15节“信息功能”中 ROW_COUNT() 所述的 功能

主要条款

optional WHERE 子句中 的条件 标识要删除的行。 如果没有 WHERE 子句,则删除所有行。

where_condition 是一个表达式,对于要删除的每一行,计算结果为true。 它的规定如 第13.2.10节“SELECT语法”中所述

如果 ORDER BY 指定了 子句,则按指定的顺序删除行。 LIMIT 子句限制了可以删除的行数。 这些子句适用于单表删除,但不适用于多表删除。

多表语法

删除[LOW_PRIORITY] [QUICK] [IGNORE]
     tbl_name[。*] [,tbl_name[。*]] ...
    来自table_references
    [地点where_condition]

删除[LOW_PRIORITY] [QUICK] [IGNORE]
    FROM tbl_name[。*] [,tbl_name[。*]] ......
    使用table_references
    [在哪里where_condition]

特权

您需要 DELETE 表上 权限才能从中删除行。 您只需要 SELECT 对只读取的任何列 权限,例如在 WHERE 子句中指定的列。

性能

当您不需要知道已删除行的数量时,该 TRUNCATE TABLE 语句是一种更快的方式来清空表而不是 DELETE 没有 WHERE 子句的语句。 不同的是 DELETE TRUNCATE TABLE 不能在事务中使用或者如果您对表有锁定。 请参见 第13.1.37节“TRUNCATE TABLE语法” 第13.3.6节“LOCK TABLES和UNLOCK TABLES语法”

删除操作的速度也可能受 第8.2.5.3节“优化DELETE语句”中 讨论的因素的影响

为确保给定 DELETE 语句不占用太多时间,特定于MySQL的 子句 指定要删除的最大行数。 如果要删除的行数大于限制,请重复该 语句,直到受影响的行数小于该 值。 LIMIT row_count DELETE DELETE LIMIT

子查询

您无法从表中删除并从子查询中的同一表中进行选择。

分区表支持

DELETE 支持使用 PARTITION 选项 显式分区选择,该 选项获取一个或多个分区或子分区(或两者)的逗号分隔名称列表,从中选择要删除的行。 未包含在列表中的分区将被忽略。 由于分区表 t 有一个名为分区 p0 ,执行该语句 DELETE FROM t PARTITION (p0) 对表作为执行相同的效果 ALTER TABLE t TRUNCATE PARTITION (p0) ; 在这两种情况下,分区 p0 中的 所有行都将 被删除。

PARTITION 可以与 WHERE 条件 一起使用 ,在这种情况下,仅对列出的分区中的行测试条件。 例如, DELETE FROM t PARTITION (p0) WHERE c < 5 仅从 p0 条件 c < 5 为true的 分区中删除行 ; 不检查任何其他分区中的行,因此不受其影响 DELETE

PARTITION 选项也可用于多表 DELETE 语句。 您可以在 FROM 选项 中指定的每个表中使用最多一个此类 选项。

有关更多信息和示例,请参见 第23.5节“分区选择”

自动增量列

如果删除包含列的最大值的行 AUTO_INCREMENT ,则不会对该 MyISAM InnoDB 重用该值 如果 模式下 删除表中的所有行 (没有 子句) ,则除了 之外 所有存储引擎的序列都将重新开始 表的 这种行为有一些例外 ,如 第15.6.1.4节“InnoDB中的AUTO_INCREMENT处理”中所述 DELETE FROM tbl_name WHERE autocommit InnoDB MyISAM InnoDB

对于 MyISAM 表,您可以 AUTO_INCREMENT 在多列键中 指定 辅助列。 在这种情况下,即使对于 MyISAM 表, 也会重复使用从序列顶部删除的值 请参见 第3.6.9节“使用AUTO_INCREMENT”

修饰符

DELETE 语句支持以下修饰符:

  • 如果指定 LOW_PRIORITY 修饰符,则服务器会延迟执行, DELETE 直到没有其他客户端从表中读取。 这会影响只使用表级锁只存储引擎(例如 MyISAM MEMORY MERGE )。

  • 对于 MyISAM 表,如果使用 QUICK 修饰符,则存储引擎在删除期间不会合并索引叶,这可能会加速某些类型的删除操作。

  • IGNORE 修改导致MySQL删除行的过程中忽略的错误。 (解析阶段遇到的错误以常规方式处理。)由于使用而 IGNORE 忽略的错误 将作为警告返回。 有关更多信息,请参阅 IGNORE关键字和严格SQL模式的比较

删除顺序

如果 DELETE 语句包含 ORDER BY 子句,则按照子句指定的顺序删除行。 这主要与结合使用有用 LIMIT 例如,以下语句查找与 WHERE 子句 匹配的行 ,对其进行排序 timestamp_column ,并删除第一个(最旧的):

从somelog中删除WHERE user ='jcole'
ORDER BY timestamp_column LIMIT 1;

ORDER BY 还有助于删除所需的顺序中的行以避免参照完整性违规。

InnoDB表

如果要从大表中删除许多行,则可能会超出表的锁定表大小 InnoDB 要避免此问题,或者只是为了最小化表保持锁定的时间,以下策略(根本不使用 DELETE )可能会有所帮助:

  1. 选择 不要 删除 的行 到与原始表具有相同结构的空表中:

    INSERT INTO t_copy SELECT * FROM t WHERE ...;
    
  2. 使用 RENAME TABLE 以原子移动原始表的方式进行,并重新命名拷贝到原来的名称:

    RENAME TABLE t TO t_old,t_copy TO t;
    
  3. 删除原始表:

    DROP TABLE t_old;
    

没有其他会话可以在 RENAME TABLE 执行时 访问所涉及的表 ,因此重命名操作不受并发问题的影响。 请参见 第13.1.36节“RENAME TABLE语法”

MyISAM表

MyISAM 表中,已删除的行在链表中维护,后续 INSERT 操作重用旧的行位置。 要回收未使用的空间并减小文件大小,请使用 OPTIMIZE TABLE 语句或 myisamchk 实用程序重新组织表。 OPTIMIZE TABLE 更容易使用,但 myisamchk 更快。 请参见 第13.7.3.4节“OPTIMIZE TABLE语法” 第4.6.4节“ myisamchk - MyISAM表维护实用程序”

QUICK 修改会影响指数的叶子是否合并的删除操作。 DELETE QUICK 对于已删除行的索引值被稍后插入的行中的类似索引值替换的应用程序最有用。 在这种情况下,将重复使用已删除值留下的孔。

DELETE QUICK 当删除的值导致未满填充的索引块跨越一系列索引值时,这些索引块将再次出现新的插入值,因此无效。 在这种情况下,使用 QUICK 会导致索引中浪费的空间仍然无法回收。 以下是此类场景的示例:

  1. 创建一个包含索引 AUTO_INCREMENT 的表

  2. 在表中插入许多行。 每个插入都会生成一个索引值,该值将添加到索引的高端。

  3. 使用删除列范围低端的行块 DELETE QUICK

在这种情况下,与已删除的索引值关联的索引块变为未填充但由于使用而未与其他索引块合并 QUICK 当新插入发生时,它们仍然未充满,因为新行在已删除范围内没有索引值。 此外,即使您稍后 DELETE 使用它们,它们仍然未充满 QUICK ,除非一些已删除的索引值恰好位于未充满的块内或附近的索引块中。 要在这些情况下回收未使用的索引空间,请使用 OPTIMIZE TABLE

如果要从表中删除许多行,则 DELETE QUICK 后续 使用可能会更快 OPTIMIZE TABLE 这会重建索引,而不是执行许多索引块合并操作。

多表删除

您可以在 DELETE 语句中 指定多个表,以 根据 WHERE 子句中 的条件从一个或多个表中删除行 您不能使用 ORDER BY LIMIT 在多表中 DELETE table_references 子句列出了连接中涉及的表,如 第13.2.10.2节“JOIN语法”中所述

对于第一个多表语法,仅 FROM 删除子句 之前列出的表中的匹配行 对于第二个多表语法,仅 删除 FROM 子句(在 USING 子句 之前 )中 列出的表中的匹配行 结果是您可以同时从多个表中删除行,并具有仅用于搜索的其他表:

删除t1,t2 FROM t1 INNER JOIN t2 INNER JOIN t3
WHERE_1.id = t2.id AND t2.id = t3.id;

要么:

从t1,t2删除使用t1 INNER JOIN t2 INNER JOIN t3
WHERE_1.id = t2.id AND t2.id = t3.id;

这些语句查找的行删除的时候,但仅删除表的匹配行使用所有三个表 t1 t2

前面的示例使用 INNER JOIN ,但多表 DELETE 语句可以使用语句中允许的其他类型的连接 SELECT ,例如 LEFT JOIN 例如,要删除不存在 t1 匹配项的行 t2 ,请使用 LEFT JOIN

删除t1 FROM t1 LEFT JOIN t2 ON t1.id = t2.id WHERE t2.id IS NULL;

语法允许 .* 在每个 语句 之后 tbl_name Access 兼容

如果您使用 DELETE 涉及 InnoDB 具有外键约束 的表的多表 语句 ,则MySQL优化器可能会按照与其父/子关系不同的顺序处理表。 在这种情况下,语句失败并回滚。 相反,您应该从单个表中删除并依赖于 提供 ON DELETE 功能, InnoDB 以便相应地修改其他表。

注意

如果声明表的别名,则在引用表时必须使用别名:

删除t1 FROM测试AS t1,test2 WHERE ...

多表中的表别名 DELETE 只应 table_references 在语句 部分声明。 在其他地方,允许别名引用但不允许别名声明。

正确:

删除a1,a2 FROM t1 AS a1 INNER JOIN t2 AS a2
WHERE a1.id = a2.id;

从a1,a2删除使用t1作为a1 INNER JOIN t2作为a2
WHERE a1.id = a2.id;

不正确:

删除t1 AS a1,t2 AS a2 FROM t1 INNER JOIN t2
WHERE a1.id = a2.id;

从t1 AS a1删除,t2 AS a2使用t1 INNER JOIN t2
WHERE a1.id = a2.id;

DELETE 从MySQL 8.0.16开始, 单表 语句 也支持表别名 (Bug#89410,Bug#27455809)

13.2.3 DO语法

DO expr[,expr] ......

DO 执行表达式但不返回任何结果。 在大多数方面,它 DO 是简写 ,但有一个优点,当你不关心结果时,它会稍微快一些。 SELECT expr, ...

DO 主要用于具有副作用的函数,例如 RELEASE_LOCK()

示例:此 SELECT 语句暂停,但也生成结果集:

MySQL的> SELECT SLEEP(5);
+ ---------- +
| 睡觉(5)|
+ ---------- +
| 0 |
+ ---------- +
1排(5.02秒)

DO 另一方面,暂停而不产生结果集:

MySQL的> DO SLEEP(5);
查询OK,0行受影响(4.99秒)

这可能很有用,例如在存储函数或触发器中,它禁止生成结果集的语句。

DO 只执行表达式。 它不能用于所有 SELECT 可以使用的情况。 例如, DO id FROM t1 无效,因为它引用了一个表。

13.2.4 HANDLER语法

HANDLER tbl_nameOPEN [[AS] alias]

HANDLER tbl_nameREAD index_name{= | <= | > = | <| >}( value1value2,...)
    [在哪里where_condition] [限制...]
HANDLER tbl_nameREAD index_name{FIRST | 下一步| 上一个| 最后}
    [在哪里where_condition] [限制...]
HANDLER tbl_nameREAD {FIRST | 下一个 }
    [在哪里where_condition] [限制...]

HANDLER tbl_name关闭

HANDLER 语句提供对表存储引擎接口的直接访问。 它适用于 InnoDB MyISAM 表。

HANDLER ... OPEN 语句打开一个表,使用后续 HANDLER ... READ 语句 可以访问它 此表对象不会被其他会话共享,并且在会话调用 HANDLER ... CLOSE 或会话终止 之前不会关闭

如果使用别名打开表,则对包含其他 HANDLER 语句 的open表的进一步引用 必须使用别名而不是表名。 如果不使用别名,但使用由数据库名称限定的表名打开表,则进一步的引用必须使用非限定表名。 例如,对于使用的表 mydb.mytable ,必须使用进一步的引用 mytable

第一个 HANDLER ... READ 语法获取指定索引满足给定值并满足 WHERE 条件的行。 如果您有多列索引,请将索引列值指定为逗号分隔列表。 指定索引中所有列的值,或指定索引列的最左前缀的值。 假设一个索引 my_idx 包括三个名为列 col_a col_b 以及 col_c 以该顺序。 HANDLER 语句可以指定索引中所有三列的值,也可以指定最左侧前缀中的列。 例如:

HANDLER ...阅读my_idx =(col_a_val,col_b_val,col_c_val)......
HANDLER ...阅读my_idx =(col_a_val,col_b_val)......
HANDLER ...阅读my_idx =(col_a_val)......

要使用 HANDLER 接口来引用表 PRIMARY KEY ,请使用带引号的标识符 `PRIMARY`

HANDLER tbl_name阅读`PRIMARY` ...

第二种 HANDLER ... READ 语法以与 WHERE 条件 匹配的索引顺序从表中获取一行

第三种 HANDLER ... READ 语法以自然行顺序从表中获取与 WHERE 条件 匹配的行 它比 需要全表扫描时 更快 自然行顺序是行存储在 表数据文件中 的顺序 此语句也适用于 表,但没有这样的概念,因为没有单独的数据文件。 HANDLER tbl_name READ index_name MyISAM InnoDB

如果没有 LIMIT 子句,所有形式的 HANDLER ... READ 获取单行(如果有)。 要返回特定数量的行,请包含 LIMIT 子句。 它具有与 SELECT 语句 相同的语法 请参见 第13.2.10节“SELECT语法”

HANDLER ... CLOSE 关闭一个打开的表 HANDLER ... OPEN

使用 HANDLER 接口而不是普通 SELECT 语句 有几个原因

  • HANDLER SELECT 以下 更快

    • 为其分配指定的存储引擎处理程序对象 HANDLER ... OPEN 该对象重 HANDLER 用于该表的 后续 语句; 它不需要为每个人重新初始化。

    • 涉及的解析较少。

    • 没有优化器或查询检查开销。

    • 处理程序接口不必提供一致的数据外观(例如, 允许 脏读 ),因此存储引擎可以使用 SELECT 通常不允许的 优化

  • HANDLER 可以更轻松地移植到使用类似低级 ISAM 接口的 MySQL应用程序 (有关 调整使用键值存储范例的应用程序的替代方法, 请参见 第15.19节“InnoDB memcached插件” 。)

  • HANDLER 使您能够以难以(甚至不可能)完成的方式遍历数据库 SELECT HANDLER 接口是与提供的交互式用户界面到数据库的应用程序时,看数据更自然的方式。

HANDLER 是一个有点低级的声明。 例如,它不提供一致性。 也就是说, HANDLER ... OPEN 走表的快照,并 不能 锁定表。 这意味着在发出 HANDLER ... OPEN 语句 ,可以修改表数据(通过当前会话或其他会话),并且这些修改可能仅部分可见 HANDLER ... NEXT HANDLER ... PREV 扫描。

打开处理程序可以关闭并标记为重新打开,在这种情况下,处理程序将丢失其在表中的位置。 当以下两种情况都成立时会发生这种情况:

  • 任何会话 FLUSH TABLES 在处理程序表上 执行 或DDL语句。

  • 处理程序处于打开状态的会话执行 HANDLER 使用表的 语句。

TRUNCATE TABLE 对于表关闭所有打开的表的处理程序 HANDLER OPEN

如果使用 打开 的表刷新表 ,则会隐式刷新处理程序并丢失其位置。 FLUSH TABLES tbl_name WITH READ LOCK HANDLER

13.2.5 IMPORT TABLE语法

进口表来自sdi_file[,sdi_file ] ......

IMPORT TABLE 语句 MyISAM 根据 .sdi (序列化字典信息)元数据文件中 包含的信息 导入 IMPORT TABLE 需要 FILE 权限来读取 .sdi 和表内容文件,以及 CREATE 要创建的表 特权。

可以使用 mysqldump 从一个服务器导出表 以编写SQL语句文件,并使用 mysql 导入到另一个服务器 以处理转储文件。 IMPORT TABLE 使用 原始 表文件 提供更快的替代方案

在导入之前,提供表内容的文件必须放在导入服务器的相应模式目录中,并且该 .sdi 文件必须位于服务器可访问的目录中。 例如, .sdi 文件可以放在 secure_file_priv 系统变量 指定的目录中 ,或者(如果 secure_file_priv 为空)放在服务器数据目录下的目录中。

以下示例描述如何 一个服务器 模式 导出已 MyISAM 命名的表 employees 并将其导入 另一个服务器 模式。 该示例使用这些假设(在您自己的系统上执行类似的操作,根据需要修改路径名称): managers hr hr

  • 对于导出服务器, export_basedir 表示其基本目录,其数据目录为 export_basedir/data

  • 对于导入服务器, import_basedir 表示其基本目录,其数据目录为 import_basedir/data

  • 表文件从导出服务器导出到 /tmp/export 目录中,并且此目录是安全的(其他用户无法访问)。

  • 导入服务器 /tmp/mysql-files 用作其 secure_file_priv 系统变量 命名的目录

要从导出服务器导出表,请使用以下过程:

  1. 通过执行此语句来锁定表以确保在导出期间无法修改表,从而确保一致的快照:

    MySQL的> FLUSH TABLES hr.employees, hr.managers WITH READ LOCK;
    

    锁定有效时,表仍然可以使用,但仅用于读取访问。

  2. 在文件系统级别,将 schema .sdi 和table内容文件从 hr schema目录 复制 到安全导出目录:

    • .sdi 文件位于 hr 架构目录中,但可能与表名称的基本名称不完全相同。 例如, .sdi 对于文件 employees managers 表可能被命名为 employees_125.sdi managers_238.sdi

    • 对于 MyISAM 表,内容文件是其 .MYD 数据文件和 .MYI 索引文件。

    给定这些文件名,复制命令如下所示:

    shell> 
    shell> 
    shell> 
    shell> 
    shell>cd export_basedir/data/hrcp employees_125.sdi /tmp/exportcp managers_238.sdi /tmp/exportcp employees.{MYD,MYI} /tmp/exportcp managers.{MYD,MYI} /tmp/export
    
  3. 解锁桌子:

    MySQL的> UNLOCK TABLES;
    

要将表导入导入服务器,请使用以下过程:

  1. 导入架构必须存在。 如有必要,执行此语句以创建它:

    MySQL的> CREATE SCHEMA hr;
    
  2. 在文件系统级别,将 .sdi 文件 复制 到导入服务器 secure_file_priv 目录, /tmp/mysql-files 另外,将表内容文件复制到 hr 架构目录:

    shell> cd /tmp/export
    shell> cp employees_125.sdi /tmp/mysql-files
    shell> cp managers_238.sdi /tmp/mysql-files
    shell> 
    shell>cp employees.{MYD,MYI} import_basedir/data/hrcp managers.{MYD,MYI} import_basedir/data/hr
    
  3. 通过执行 IMPORT TABLE 命名的语句来 导入表 .sdi 文件

    MySQL的> IMPORT TABLE FROM
           '/tmp/mysql-files/employees.sdi',
           '/tmp/mysql-files/managers.sdi';
    

如果该变量为空,则 .sdi 不需要 将该 文件放在 secure_file_priv 系统变量 指定的导入服务器目录中 ; 它可以位于服务器可访问的任何目录中,包括导入表的架构目录。 .sdi 但是, 如果 文件放在该目录中,则可以重写; 导入操作会 .sdi 为表 创建一个新 文件, .sdi 如果操作对新文件使用相同的文件名 ,则会覆盖旧 文件。

每个 sdi_file 值必须是一个字符串文字, .sdi 用于为表 命名 文件或者是与 .sdi 文件 匹配的模式 如果字符串是模式,则 .sdi 必须按字面指定 任何前导目录路径和 文件名后缀。 仅在文件名的基本名称部分允许使用模式字符:

  • ? 匹配任何单个字符

  • * 匹配任何字符序列,包括没有字符

使用模式,前面的 IMPORT TABLE 语句可能是这样编写的(假设该 /tmp/mysql-files 目录不包含其他 语句) .sdi 与模式匹配的 文件):

IMPORT TABLE FROM'/ tmp / mysql-files / *。sdi';

要解释 .sdi 文件路径名 的位置 ,服务器将使用与 IMPORT TABLE 服务器端规则 相同的规则 LOAD DATA (即非 LOCAL 规则)。 请参见 第13.2.7节“LOAD DATA语法” ,特别注意用于解释相对路径名的规则。

IMPORT TABLE 如果无法找到 .sdi 或表文件,则会 失败 导入表后,服务器会尝试打开它,并在检测到任何问题时报告为警告。 要尝试修复以更正任何报告的问题,请使用 REPAIR TABLE

IMPORT TABLE 没有写入二进制日志。

限制和限制

IMPORT TABLE 仅适用于非 TEMPORARY MyISAM 表格。 它不适用于使用事务存储引擎创建的表,使用创建的表 CREATE TEMPORARY TABLE 或视图。

除非导出服务器上定义的表使用 DATA DIRECTORY INDEX DIRECTORY 表选项 ,否则必须在导入操作之前将表数据和索引文件放在导入服务器的模式目录中 在这种情况下,在执行 IMPORT TABLE 语句 之前使用以下备选方案之一修改导入过程

  • 将数据和索引文件放在导入服务器主机上与导出服务器主机上相同的目录中,并在导入服务器模式目录中为这些文件创建符号链接。

  • 将数据和索引文件放入与导出服务器主机上的导入服务器主机目录不同的导入服务器主机目录中,并在导入服务器模式目录中为这些文件创建符号链接。 此外,修改 .sdi 文件以反映不同的文件位置。

  • 将数据和索引文件放入导入服务器主机上的架构目录中,并修改该 .sdi 文件以删除数据和索引目录表选项。

存储在 .sdi 文件 中的任何归类ID 必须引用导出和导入服务器上的相同归类。

表的触发器信息未序列化到表 .sdi 文件中,因此导入操作不会还原触发器。

.sdi 在执行 IMPORT TABLE 语句 之前允许 文件进行 一些编辑 ,而其他文件是有问题的,甚至可能导致导入操作失败:

  • 如果导出和导入服务器之间的数据和索引文件的位置不同,则需要更改数据目录和索引目录表选项。

  • 需要更改模式名称才能将表导入导入服务器上的不同模式,而不是导出服务器上。

  • 可能需要更改模式和表名称以适应导出和导入服务器上的文件系统区分大小写语义之间的差异或 lower_case_table_names 设置的 差异 更改 .sdi 文件中 的表名 可能也需要重命名表文件。

  • 在某些情况下,允许更改列定义。 更改数据类型可能会导致问题。

13.2.6 INSERT语法

INSERT [LOW_PRIORITY | 延迟| HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name
    [PARTITION(partition_name[,partition_name ] ...)]
    [(col_name[,col_name] ......)]
    {VALUES | VALUE}(value_list)[,(value_list)] ......
    [ON DUPLICATE KEY UPDATE assignment_list]

INSERT [LOW_PRIORITY | 延迟| HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name
    [PARTITION(partition_name[,partition_name ] ...)]
    SET assignment_list
    [ON DUPLICATE KEY UPDATE assignment_list]

INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name
    [PARTITION(partition_name[,partition_name ] ...)]
    [(col_name[,col_name] ......)]
    选择 ...
    [ON DUPLICATE KEY UPDATE assignment_list]

value
    { expr| 默认}

value_listvalue[,value] ......

assignmentcol_name=value

assignment_listassignment[,assignment] ......

INSERT 将新行插入现有表中。 INSERT ... VALUES INSERT ... SET 语句的形式插入基于明确指定的值的行。 INSERT ... SELECT 形式插入从另一个或多个表中选择行。 如果要插入的行会导致 索引中 的重复值,则 INSERT 使用 ON DUPLICATE KEY UPDATE 子句可以更新现有行 UNIQUE PRIMARY KEY

有关更多信息 INSERT ... SELECT ,并 INSERT ... ON DUPLICATE KEY UPDATE 请参见 第13.2.6.1,“INSERT ... SELECT语法” 第13.2.6.2,“插入...对重复密钥更新语法”

在MySQL 8.0中, DELAYED 关键字被接受但被服务器忽略。 有关此原因,请参见 第13.2.6.3节“INSERT DELAYED语法”

插入表需要表的 INSERT 权限。 如果使用该 ON DUPLICATE KEY UPDATE 子句并且重复键导致 UPDATE 执行,则该语句需要 UPDATE 更新列 权限。 对于已读但未修改的列,您只需要该 SELECT 权限(例如,对于仅在 子句中 col_name = expr 赋值 的右侧引用的列 ON DUPLICATE KEY UPDATE )。

插入分区表时,可以控制哪些分区和子分区接受新行。 PARTITION 选项获取表的一个或多个分区或子分区(或两者)的逗号分隔名称列表。 如果给定 INSERT 语句 要插入的任何行与 列出的其中一个分区不匹配,则该 INSERT 语句将失败,并显示错误“ 找到与给定分区集不匹配的行” 有关更多信息和示例,请参见 第23.5节“分区选择”

您可以使用 REPLACE 而不是 INSERT 覆盖旧行。 REPLACE INSERT IGNORE 处理包含复制旧行的唯一键值的新行 的对应物 :新行替换旧行而不是丢弃。 请参见 第13.2.9节“REPLACE语法”

tbl_name 是应该插入行的表。 指定语句提供值的列,如下所示:

  • 在表名后面提供以逗号分隔的列名的括号列表。 在这种情况下,每个命名列的值必须由 VALUES 列表或 SELECT 语句提供。

  • 如果没有为 INSERT ... VALUES or 指定列名列表, INSERT ... SELECT 则表中每列的值必须由 VALUES 列表或 SELECT 语句提供。 如果您不知道表中列的顺序,请使用 以查找。 DESCRIBE tbl_name

  • SET 子句表示列明确地通过名称,与分配每一个的值一起。

列值可以通过多种方式给出:

  • 如果未启用严格SQL模式,则任何未显式赋值的列都将设置为其默认值(显式或隐式)。 例如,如果指定的列列表未指定表中的所有列,则将未命名的列设置为其默认值。 第11.7节“数据类型默认值”中 描述了默认值分配 另请参见 第1.8.3.3节“无效数据的约束”

    如果启用了严格SQL模式,则如果 INSERT 语句没有为没有默认值的每个列指定显式值 ,则会 生成错误。 请参见 第5.1.11节“服务器SQL模式”

  • 如果列列表和 VALUES 列表都为空, INSERT 创建一行,并将每列设置为其默认值:

    插入 tbl_name()VALUES();
    

    如果未启用严格模式,则MySQL会对没有显式定义的默认值的任何列使用隐式默认值。 如果启用了严格模式,则如果任何列没有默认值,则会发生错误。

  • 使用关键字 DEFAULT 将列显式设置为其默认值。 这使得编写 INSERT 为除了几列之外的所有列分配值的语句 变得更容易 ,因为它使您能够避免编写 VALUES 不包含表中每列的值 的不完整 列表。 否则,您必须提供与列表中每个值对应的列名 VALUES 列表。

  • 如果显式插入生成的列,则唯一允许的值为 DEFAULT 有关生成的列的信息,请参见 第13.1.20.9节“创建表和生成的列”

  • 在表达式中,您可以使用它 来生成列的默认值 DEFAULT(col_name) col_name

  • expr 如果表达式数据类型与列数据类型不匹配,则可能会发生提供列值 的表达式的类型转换 转换给定值可能会导致不同的插入值,具体取决于列类型。 例如,将所述字符串 '1999.0e-2' INT FLOAT DECIMAL(10,6) ,或 YEAR 列中的值插入 1999 19.9921 19.992100 ,或 1999 ,分别。 存储在 INT YEAR 列中 的值 1999 因为字符串到数字的转换只能看到字符串的初始部分,因为它可能被视为有效的整数或年份。 对于 FLOAT DECIMAL 列,字符串到数字的转换将整个字符串视为有效的数值。

  • 表达式 expr 可以引用先前在值列表中设置的任何列。 例如,您可以执行此操作,因为 之前已分配的 col2 引用 col1

    INSERT INTO tbl_name(col1,col2)VALUES(15,col1 * 2);
    

    但以下是不合法的,因为参考的值是 col1 col2 之后的 col1

    INSERT INTO tbl_name(col1,col2)VALUES(col2 * 2,15);
    

    包含 AUTO_INCREMENT 值的 列发生异常 由于 AUTO_INCREMENT 值是在其他值赋值之后生成的 AUTO_INCREMENT ,因此对赋值中 列的 任何引用都会 返回a 0

INSERT 使用的陈述 VALUES 语法的语句可以插入多行。 为此,请包含多个以逗号分隔的列值列表,其中列表括在括号中并用逗号分隔。 例:

插入 tbl_name(a,b,c)值(1,2,3),(4,5,6),(7,8,9);

每个值列表必须包含与每行插入的值完全相同的值。 以下语句无效,因为它包含一个包含九个值的列表,而不是三个包含三个值的列表:

插入tbl_name(a,b,c)价值观(1,2,3,4,5,6,7,8,9);

VALUE VALUES 这种情况下 的同义词 既不会暗示值列表的数量,也不暗示每个列表的值的数量。 无论是单个值列表还是多个列表,都可以使用,无论每个列表的值的数量是多少。

INSERT 可以使用 ROW_COUNT() SQL函数或 mysql_affected_rows() C API函数 获取 an的affected-rows值 请参见 第12.15节“信息函数” 第28.7.7.1节“mysql_affected_rows()”

如果使用 INSERT ... VALUES 带有多个值列表 INSERT ... SELECT 的语句,则该语句将返回以下格式的信息字符串:

记录:N1重复:N2警告:N3

如果您使用的是C API,则可以通过调用该 mysql_info() 函数 来获取信息字符串 请参见 第28.7.7.36节“mysql_info()”

Records 表示语句处理的行数。 (这不一定是实际插入的行数,因为 Duplicates 它可能非零。) Duplicates 表示无法插入的行数,因为它们会复制某些现有的唯一索引值。 Warnings 表示以某种方式插入有问题的列值的尝试次数。 在以下任何条件下都可能发生警告:

  • 插入 NULL 已声明的列 NOT NULL 对于多行 INSERT 语句或 INSERT INTO ... SELECT 语句,该列设置为列数据类型的隐式默认值。 这适用 0 于数字类型,字符串类型为空字符串( '' ,日期和时间类型为 值。 INSERT INTO ... SELECT 语句的处理方式与多行插入的处理方式相同,因为服务器不检查结果集 SELECT 以查看它是否返回单行。 (对于单行 INSERT NULL 插入 时不会发出警告 NOT NULL 柱。 相反,该语句失败并出现错误。)

  • 将数字列设置为位于列范围之外的值。 该值将剪切到范围的最近端点。

  • 将值分配 '10.34 a' 给数字列。 将删除尾随的非数字文本,并插入剩余的数字部分。 如果字符串值没有前导数字部分,则列设置为 0

  • 插入一个字符串转换成一个字符串柱( CHAR VARCHAR TEXT ,或 BLOB ),其超过了列的最大长度。 该值将截断为列的最大长度。

  • 将值插入对数据类型不合法的日期或时间列。 该列设置为该类型的适当零值。

  • 有关 列值的 INSERT 示例 AUTO_INCREMET ,请参见 第3.6.9节“使用AUTO_INCREMENT”

    如果 INSERT 将行插入到具有 AUTO_INCREMENT 的表中,则 可以使用 LAST_INSERT_ID() SQL函数或 mysql_insert_id() C API函数 找到用于该列的值

    注意

    这两个函数的行为并不总是相同。 第12.15节“信息函数” 第28.7.7.38节“mysql_insert_id()”中 进一步讨论了有关列 INSERT 语句 行为 AUTO_INCREMENT

INSERT 语句支持以下修饰符:

  • 如果使用 LOW_PRIORITY 修饰符, INSERT 则会延迟 执行, 直到没有其他客户端从表中读取。 这包括在现有客户端正在阅读时开始阅读的其他客户端,以及 INSERT LOW_PRIORITY 语句等待时。 因此,发布 INSERT LOW_PRIORITY 语句 的客户端可能 需要等待很长时间。

    LOW_PRIORITY 影响使用仅表级锁定仅存储引擎(如 MyISAM MEMORY ,和 MERGE )。

    注意

    LOW_PRIORITY 通常不应该与 MyISAM 一起使用, 因为这样做会禁用并发插入。 请参见 第8.11.3节“并发插入”

  • 如果指定 HIGH_PRIORITY ,则在 --low-priority-updates 使用该选项启动服务器时 ,它将覆盖该 选项 的效果 它还会导致不使用并发插入。 请参见 第8.11.3节“并发插入”

    HIGH_PRIORITY 影响使用仅表级锁定仅存储引擎(如 MyISAM MEMORY ,和 MERGE )。

  • 如果使用 IGNORE 修饰符, INSERT 则忽略 执行 语句 时发生的错误 例如,如果没有 IGNORE ,则复制 表中 现有 UNIQUE 索引或 PRIMARY KEY 的行 会导致重复键错误,并且语句将中止。 使用时 IGNORE ,该行将被丢弃并且不会发生错误。 忽略的错误会生成警告。

    IGNORE 对插入到分区表中的效果类似,其中没有找到与给定值匹配的分区。 没有 IGNORE ,这样的 INSERT 语句会因错误而中止。 INSERT IGNORE 被使用时,插入操作默默地失效含有不匹配的值的行,但会插入匹配的行。 有关示例,请参见 第23.2.2节“LIST分区”

    如果 IGNORE 未指定 ,将触发错误的数据转换将中止语句 使用时 IGNORE ,将无效值调整为最接近的值并插入; 产生警告,但声明不会中止。 您可以使用 mysql_info() C API函数 确定 实际插入表中的行数。

    有关更多信息,请参阅 IGNORE关键字和严格SQL模式的比较

  • 如果指定 ON DUPLICATE KEY UPDATE ,行插入,将在导致重复值 UNIQUE 索引或者 PRIMARY KEY ,一个 UPDATE 旧行的发生。 如果将行作为新行插入,则每行的受影响行值为1;如果更新现有行,则为2,如果现有行设置为其当前值,则为0。 如果 在连接到 mysqld 指定 C API函数 CLIENT_FOUND_ROWS 标志,则 如果将现有行设置为其当前值,则affected-rows值为1(不为0)。 请参见 第13.2.6.2节“INSERT ... ON DUPLICATE KEY UPDATE语法” mysql_real_connect()

  • INSERT DELAYED 在MySQL 5.6中已弃用,并计划最终删除。 在MySQL 8.0中, DELAYED 修饰符被接受但被忽略。 使用 INSERT (不 DELAYED )代替。 请参见 第13.2.6.3节“INSERT DELAYED语法”

INSERT 使用存储引擎(例如 MyISAM 使用表级锁) 影响分区表 语句 仅锁定实际插入行的分区。 (对于 InnoDB 使用行级锁定的 存储引擎 ,不会发生分区锁定。)有关更多信息,请参阅 分区和锁定

13.2.6.1 INSERT ... SELECT语法

INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
    [INTO] tbl_name
    [PARTITION(partition_name[,partition_name ] ...)]
    [(col_name[,col_name] ......)]
    选择 ...
    [ON DUPLICATE KEY UPDATE assignment_list]

value
    { expr| 默认}

assignmentcol_name=value

assignment_listassignment[,assignment] ......

使用 INSERT ... SELECT ,您可以根据 SELECT 语句 的结果快速将多行插入到表中,该 语句可以从一个或多个表中进行选择。 例如:

INSERT INTO tbl_temp2(fld_id)
  SELECT tbl_temp1.fld_order_id
  FROM tbl_temp1 WHERE tbl_temp1.fld_order_id> 100;

以下条件适用于 INSERT ... SELECT 陈述:

  • 指定 IGNORE 忽略会导致重复键违规的行。

  • INSERT 语句 的目标表 可能出现在 查询部分 FROM 子句中 SELECT 但是,您无法插入表中并从子查询中的同一表中进行选择。

    当从同一个表中进行选择和插入时,MySQL会创建一个内部临时表来保存行中的行 SELECT ,然后将这些行插入到目标表中。 但是,您不能 INSERT INTO t ... SELECT ... FROM t 在何时 t 使用 TEMPORARY 表,因为 TEMPORARY 表不能在同一语句中引用两次。 请参见 第8.4.4节“MySQL中的内部临时表使用” 第B.4.6.2节“临时表问题”

  • AUTO_INCREMENT 列像往常一样工作。

  • 为确保二进制日志可用于重新创建原始表,MySQL不允许对 INSERT ... SELECT 语句 进行并发插入 (请参见 第8.11.3节“并发插入” )。

  • 为了避免 SELECT INSERT 引用同一个表 时出现模糊的列引用问题 请为 SELECT 部件 中使用的每个表提供唯一的别名 ,并使用适当的别名限定 部分中的列名。

您可以显式选择源表或目标表(或两者)的哪些分区或子分区(或两者)与表 PARTITION 的名称后面的选项 一起使用 如果 在语句 PARTITION SELECT 部分 中使用源表的名称,则 仅从其分区列表中指定的分区或子分区中选择行。 PARTITION INSERT 语句部分 的目标表的名称一起使用时 ,必须可以将选定的所有行插入到该选项后面的分区列表中指定的分区或子分区中。 否则,该 INSERT ... SELECT 语句失败。 有关更多信息和示例,请参阅 第23.5节“分区选择”

有关 INSERT ... SELECT 语句,请参见 第13.2.6.2节“INSERT ... ON DUPLICATE KEY UPDATE语法”, 了解 SELECT 可在 ON DUPLICATE KEY UPDATE 子句中 引用列的 条件

SELECT 带有no ORDER BY 子句的语句返回行 的顺序 是不确定的。 这意味着,在使用复制时,无法保证此类 SELECT 在主服务器和从服务器上以相同的顺序返回行,这可能导致它们之间的不一致。 要防止这种情况发生,请始终 INSERT ... SELECT 使用 ORDER BY 在主服务器和从服务器上生成相同行顺序 子句 编写 要复制的 语句。 另请参见 第17.4.1.18节“复制和限制”

由于这个问题, INSERT ... SELECT ON DUPLICATE KEY UPDATE INSERT IGNORE ... SELECT 声明是基于语句的复制标记为不安全。 当使用基于语句的模式时,此类语句在错误日志中生成警告,并在使用 MIXED 模式 时使用基于行的格式写入二进制日志 (Bug#11758262,Bug#50439)

另请参见 第17.2.1.1节“基于语句和基于行的复制的优点和缺点”

INSERT ... SELECT 使用存储引擎(例如 MyISAM 使用表级锁) 影响分区表 语句 会锁定目标表的所有分区; 但是,只有那些实际从源表中读取的分区才会被锁定。 (对于使用存储引擎的表,例如 InnoDB 使用行级锁定的 表,不会发生这种情况 。)有关更多信息,请参阅 分区和锁定

13.2.6.2 INSERT ... ON DUPLICATE KEY UPDATE语法

如果指定 ON DUPLICATE KEY UPDATE 子句并且要插入的行将导致 UNIQUE 索引中 出现重复值, 则会出现旧行的 PRIMARY KEY 某个 UPDATE 行。 例如,如果将column a 声明为 UNIQUE 并包含该值 1 ,则以下两个语句具有类似的效果:

插入t1(a,b,c)值(1,2,3)
  ON DUPLICATE KEY UPDATE c = c + 1;

更新t1 SET c = c + 1 WHERE a = 1;

(对于 自动增量列 InnoDB 表, 效果不相同 a 。对于自动增量列, INSERT 语句会增加自动增量值,但 UPDATE 不会。)

如果column b 也是唯一的, INSERT 则相当于此 UPDATE 语句:

UPDATE t1 SET c = c + 1 WHERE a = 1 OR b = 2 LIMIT 1;

如果 a=1 OR b=2 几个行相匹配,只有 一个 行被更新。 通常,您应该尽量避免 ON DUPLICATE KEY UPDATE 在具有多个唯一索引的表上 使用 子句。

对于 ON DUPLICATE KEY UPDATE ,如果将行作为新行插入,则每行的受影响行值为1;如果更新现有行,则为2,如果现有行设置为其当前值,则为0。 如果 在连接到 mysqld 指定 C API函数 CLIENT_FOUND_ROWS 标志,则 如果将现有行设置为其当前值,则affected-rows值为1(不为0)。 mysql_real_connect()

如果表包含 AUTO_INCREMENT 列并 INSERT ... ON DUPLICATE KEY UPDATE 插入或更新行,则该 LAST_INSERT_ID() 函数返回该 AUTO_INCREMENT 值。

ON DUPLICATE KEY UPDATE 子句可以包含多个列分配,以逗号分隔。

ON DUPLICATE KEY UPDATE 子句 中的赋值表达式中 ,您可以使用该 函数来引用 语句 部分中的 列值 换句话说, 子句中引用了 将插入 的值 ,没有发生重复键冲突。 此功能在多行插入中特别有用。 函数仅在 子句或 语句中 有意义 否则 返回 例: VALUES(col_name) INSERT INSERT ... ON DUPLICATE KEY UPDATE VALUES(col_name) ON DUPLICATE KEY UPDATE col_name VALUES() ON DUPLICATE KEY UPDATE INSERT NULL

插入t1(a,b,c)值(1,2,3),(4,5,6)
  ON DUPLICATE KEY UPDATE c = VALUES(a)+ VALUES(b);

该陈述与以下两个陈述相同:

插入t1(a,b,c)值(1,2,3)
  ON DUPLICATE KEY UPDATE c = 3;
插入到t1(a,b,c)值(4,5,6)
  ON DUPLICATE KEY UPDATE c = 9;

对于 INSERT ... SELECT 语句,这些规则适用于 SELECT 您可以在 ON DUPLICATE KEY UPDATE 子句中 引用的 可接受形式的 查询表达式

  • 对单个表上的查询的列的引用,该表可以是派生表。

  • 对多个表上的连接的查询引用列。

  • 引用 DISTINCT 查询中的

  • 引用其他表中的列,只要 SELECT 不使用 GROUP BY 一个副作用是您必须限定对非唯一列名的引用。

UNION 不支持 对a 列的引用 要解决此限制,请将 UNION 重写 为派生表,以便可以将其行视为单表结果集。 例如,此语句产生错误:

插入到t1(a,b)
  SELECT c,d FROM t2
  联盟
  SELECT e,f FROM t3
ON DUPLICATE KEY UPDATE b = b + c;

相反,使用重写 UNION 为派生表 的等效语句

插入到t1(a,b)
SELECT * FROM
  (SELECT c,d FROM t2
   联盟
   选择e,f FROM t3)AS dt
ON DUPLICATE KEY UPDATE b = b + c;

将查询重写为派生表的技术还允许从 GROUP BY 查询中 引用列

因为 INSERT ... SELECT 语句 的结果 取决于来自的 SELECT 顺序,并且无法始终保证此顺序,所以当 INSERT ... SELECT ON DUPLICATE KEY UPDATE 主服务器和从服务器的 日志记录 发散 时,可能会发生这种情况 因此, INSERT ... SELECT ON DUPLICATE KEY UPDATE 语句被标记为基于语句的复制不安全。 当使用基于语句的模式时,此类语句在错误日志中生成警告,并在使用 MIXED 模式 时使用基于行的格式写入二进制日志 INSERT ... ON DUPLICATE KEY UPDATE 对具有多个唯一键或主键的表 声明也标记为不安全。 (Bug#11765650,Bug#58637)

另请参见 第17.2.1.1节“基于语句和基于行的复制的优点和缺点”

一个 INSERT ... ON DUPLICATE KEY UPDATE 使用的存储引擎,诸如分区表 MyISAM ,其使用表级锁锁定在其中一个分区键列被更新表中的任何分区。 (对于使用存储引擎的表,例如 InnoDB 使用行级锁定的 表,不会发生这种情况 。)有关更多信息,请参阅 分区和锁定

13.2.6.3 INSERT DELAYED语法

INSERT DELAYED ...

语句 DELAYED 选项 INSERT 是标准SQL的MySQL扩展。 在以前版本的MySQL中,它可以用于某些类型的表(例如 MyISAM ),这样当客户端使用时 INSERT DELAYED ,它可以立即从服务器获得,并且当表不是时,行排队等待插入由任何其他线程使用。

DELAYED MySQL 5.6中不推荐使用插入和替换。 在MySQL 8.0中, DELAYED 不受支持。 服务器识别但忽略 DELAYED 关键字,将插入作为非延迟插入处理,并生成 ER_WARN_LEGACY_SYNTAX_CONVERTED 警告( 不再支持INSERT DELAYED。语句已转换为INSERT )。 DELAYED 关键字计划在将来的版本中删除。

13.2.7 LOAD DATA语法

负载数据
    [LOW_PRIORITY | CONCURRENT] [当地]
    INFILE' file_name'
    [REPLACE | 忽视]
    INTO TABLE tbl_name
    [PARTITION(partition_name[,partition_name] ...)]
    [字符集charset_name]
    [{FIELDS | 列}
        [终止于' string']
        [[OPTIONALLY]封闭' char']
        [ESCAPED BY' char']
    ]
    [LINES
        [开始' string']
        [终止于' string']
    ]
    [IGNORE number{LINES | ROWS}]
    [(col_name_or_user_var
        [,col_name_or_user_var] ......)]
    [SET col_name= { expr| 默认},
        [,col_name= { expr| DEFAULT}] ...]

LOAD DATA 语句以非常高的速度将文本文件中的行读入表中。 LOAD DATA 是补充 SELECT ... INTO OUTFILE (请参见 第13.2.10.1节“SELECT ... INTO语法” 。)要将表中的数据写入文件,请使用 SELECT ... INTO OUTFILE 要将文件读回表中,请使用 LOAD DATA 两个语句 FIELDS LINES 子句 的语法 相同。

您还可以使用 mysqlimport 实用程序 加载数据文件 ; 请参见 第4.5.5节“ mysqlimport - 数据导入程序” mysqlimport 通过向 LOAD DATA 服务器 发送 语句来进行操作。

有关效率的详细信息 INSERT LOAD DATA 和加速 LOAD DATA ,请参见 第8.2.5.1,“优化INSERT语句”

分区表支持

LOAD DATA 支持显式分区选择,使用 PARTITION 带有一个或多个以逗号分隔的分区,子分区或两者的名称列表 选项。 使用此选项时,如果文件中的任何行无法插入列表中指定的任何分区或子分区,则语句将失败,并显示错误“ 找到与给定分区集不匹配的行” 有关更多信息和示例,请参见 第23.5节“分区选择”

对于使用使用表锁的存储引擎的分区表,例如 MyISAM LOAD DATA 无法修剪任何分区锁。 这不适用于使用采用行级锁定的存储引擎的表,例如 InnoDB 有关更多信息,请参阅 分区和锁定

输入文件名,位置和内容解释

文件名必须以文字字符串形式给出。 在Windows上,将路径名中的反斜杠指定为正斜杠或加倍反斜杠。 character_set_filesystem 系统变量控制的文件名字符集的解释。

服务器使用 character_set_database 系统变量 指示的字符集 来解释文件中的信息。 SET NAMES 并且设置 character_set_client 不影响输入的解释。 如果输入文件的内容使用的字符集与默认值不同,通常最好使用该 CHARACTER SET 子句 指定文件的字符集 字符集 binary 指定 无转换。

LOAD DATA 无论加载字段值的列的数据类型如何,都将文件中的所有字段解释为具有相同的字符集。 要正确解释文件内容,必须确保使用正确的字符集编写它。 例如,如果使用 mysqldump -T 编写数据文件 SELECT ... INTO OUTFILE mysql中 发出 语句 ,请务必使用 --default-character-set 选项,以便在加载文件时使用的字符集中输出输出 LOAD DATA

注意

这是不可能的加载使用数据文件 ucs2 utf16 utf16le ,或者 utf32 字符集。

并发注意事项

如果使用 LOW_PRIORITY 修饰符,则 LOAD DATA 语句的 执行将 延迟,直到没有其他客户端从表中读取。 这会影响只使用表级锁只存储引擎(例如 MyISAM MEMORY MERGE )。

如果使用 满足并发插入条件 CONCURRENT MyISAM 指定 修饰符 (即,它在中间不包含空闲块),则其他线程可以在 LOAD DATA 执行时 从表中检索数据 LOAD DATA 即使没有其他线程同时使用该表, 此修饰符 也会 影响 的性能

有关 LOAD DATA 复制的信息,请参见 第17.4.1.19节“复制和装入数据”

LOCAL 修改影响的文件和错误处理预期的位置,如下文所述。 LOCAL 仅当您的服务器和客户端都已配置为允许它时才有效。 例如,如果 mysqld local_infile 禁用系统变量的情况 下启动 LOCAL 则不起作用。 请参见 第6.1.6节“LOAD DATA LOCAL的安全问题”

LOCAL 修改会影响该文件预计将发现:

  • 如果 LOCAL 指定,则文件由客户端主机上的客户端程序读取并发送到服务器。 该文件可以作为完整路径名提供,以指定其确切位置。 如果以相对路径名的形式给出,则相对于启动客户端程序的目录解释名称。

    使用 LOCAL LOAD DATA ,会在MySQL服务器存储临时文件的目录中创建该文件的副本。 请参见 第B.4.3.5节“MySQL存储临时文件的位置” 此目录中的副本缺少足够的空间可能导致 LOAD DATA LOCAL 语句失败。

  • 如果 LOCAL 未指定,则文件必须位于服务器主机上,并由服务器直接读取。 服务器使用以下规则来定位文件:

    • 如果文件名是绝对路径名,则服务器将其用作给定的名称。

    • 如果文件名是具有一个或多个前导组件的相对路径名,则服务器将搜索相对于服务器数据目录的文件。

    • 如果给出没有前导组件的文件名,则服务器在默认数据库的数据库目录中查找该文件。

在非本 LOCAL 例中,这些规则意味着 ./myfile.txt 从服务器的数据目录 myfile.txt 中读取 名为的文件,而 从默认数据库的数据库目录中读取 名为的文件 例如,如果 db1 是缺省数据库,则以下 LOAD DATA 语句 data.txt 将从数据库目录中 读取该文件 db1 ,即使该语句显式将该文件加载到 db2 数据库中 的表中

LOAD DATA INFILE'Data.txt'INTO TABLE db2.my_table;
注意

服务器还使用非 LOCAL 规则来定位 语句的 .sdi 文件 IMPORT TABLE

LOCAL 加载操作读取位于服务器上的文本文件。 出于安全原因,此类操作要求您拥有该 FILE 权限。 请参见 第6.2.2节“MySQL提供的权限” 此外,非 LOCAL 加载操作受 secure_file_priv 系统变量设置的限制。 如果变量值是非空目录名,则要加载的文件必须位于该目录中。 如果变量值为空(这是不安全的),则文件只需要服务器可读。

使用 LOCAL 比让服务器直接访问文件要慢一些,因为文件内容必须通过客户端连接发送到服务器。 另一方面,您不需要该 FILE 权限来加载本地文件。

LOCAL 也会影响错误处理:

  • 使用 LOAD DATA ,数据解释和重复键错误会终止操作。

  • 随着 LOAD DATA LOCAL ,数据解释和重复键错误成为警告,并且操作继续,因为服务器无法在操作过程中停止传输文件。 对于重复键错误,这与 IGNORE 指定 的相同 IGNORE 本节后面将进一步解释。

重复键处理

REPLACE IGNORE 输入行的修饰处理控制复制唯一键值的现有行:

  • 如果指定 REPLACE ,则输入行将替换现有行。 换句话说,主键或唯一索引的值与现有行的值相同。 请参见 第13.2.9节“REPLACE语法”

  • 如果指定 IGNORE ,则会丢弃复制唯一键值上现有行的行。 有关更多信息,请参阅 IGNORE关键字和严格SQL模式的比较

  • 如果未指定任何修饰符,则行为取决于是否 LOCAL 指定 修饰符。 如果没有 LOCAL ,则在找到重复键值时会发生错误,并忽略文本文件的其余部分。 使用时 LOCAL ,默认行为与 IGNORE 指定 的相同 ; 这是因为服务器无法在操作过程中停止传输文件。

索引处理

要在加载操作期间忽略外键约束,请在执行 SET foreign_key_checks = 0 前执行语句 LOAD DATA

如果 LOAD DATA 在空 MyISAM 表上使用,则所有非唯一索引都在单独的批处理中创建(至于 REPAIR TABLE )。 通常, LOAD DATA 当您有许多索引时 ,这会 更快。 在某些极端情况下,您可以通过 ALTER TABLE ... DISABLE KEYS 在将文件加载到表中之前 关闭它们 并使用 ALTER TABLE ... ENABLE KEYS 在加载文件后重新创建索引来 更快地 创建索引。 请参见 第8.2.5.1节“优化INSERT语句”

现场和线路处理

对于 LOAD DATA SELECT ... INTO OUTFILE 语句, FIELDS LINES 子句 的语法 是相同的。 两个子句都是可选的,但 FIELDS 必须在 LINES 两者都指定 之前

如果指定 FIELDS 子句,则每个子句( TERMINATED BY [OPTIONALLY] ENCLOSED BY ESCAPED BY )也是可选的,但必须至少 指定其中一个 子句 允许这些子句的参数仅包含ASCII字符。

如果指定no FIELDS LINES clause,则默认值与您编写的相同:

由''''''''''''''''''''''''''''''''''''''''''''''''''''
由'\ n'开始''终止的线路''

反斜杠是SQL语句中字符串中的MySQL转义字符。 因此,要指定文字反斜杠,必须为该值指定两个反斜杠,以将其解释为单个反斜杠。 转义序列 '\t' 并分别 '\n' 指定制表符和换行符。

换句话说,默认值导致 LOAD DATA 在读取输入时如下操作:

  • 在换行符处查找行边界。

  • 不要跳过任何行前缀。

  • 将行分隔为选项卡中的字段。

  • 不要指望字段包含在任何引用字符中。

  • 将转义字符前面的字符解释 \ 为转义序列。 例如, \t \n ,和 \\ 分别表示选项卡,换行,反斜线。 有关 FIELDS ESCAPED BY 转义序列的完整列表, 请参阅 稍后 的讨论

相反,默认值导致 SELECT ... INTO OUTFILE 在写入输出时如下操作:

  • 在字段之间写标签。

  • 不要在任何引号字符中包含字段。

  • 使用 \ 逃脱制表符,换行符的情况下,或 \ 字段值内出现。

  • 在行的末尾写下换行符。

注意

对于在Windows系统上生成的文本文件,可能需要正确读取文件, LINES TERMINATED BY '\r\n' 因为Windows程序通常使用两个字符作为行终止符。 某些程序(如 写字板) \r 在编写文件时 可能会 用作行终止符。 要阅读此类文件,请使用 LINES TERMINATED BY '\r'

如果所有输入行都有一个您想要忽略的公共前缀,则可以使用 跳过前缀 和前面的任何内容 如果一行不包含前缀,则跳过整行。 假设您发出以下语句: LINES STARTING BY 'prefix_string'

LOAD DATA INFILE'/tmp/test.txt'INTO TABLE test
  字段由'''起点'xxx'终止;

如果数据文件如下所示:

XXX “ABC”,1
东西xxx“def”,2
“GHI”,3

生成的行将是 ("abc",1) ("def",2) 跳过文件中的第三行,因为它不包含前缀。

选项可用于忽略文件开头的行。 例如,您可以使用 跳过包含列名的初始标题行: IGNORE number LINES IGNORE 1 LINES

LOAD DATA INFILE'/tmp/test.txt'INTO TABLE test IGNORE 1 LINES;

当您 SELECT ... INTO OUTFILE 串联使用 LOAD DATA 以将数据从数据库写入文件然后稍后将文件读回数据库时,两个语句的字段和行处理选项必须匹配。 否则, LOAD DATA 将无法正确解释文件的内容。 假设您使用 SELECT ... INTO OUTFILE 逗号分隔的字段来编写文件:

SELECT * INTO OUTFILE'Data.txt'
  字段被','终止
  FROM table2;

要读取逗号分隔的文件,正确的语句将是:

LOAD DATA INFILE'Data.txt'INTO TABLE table2
  FIELDS终止',';

如果你试图用下面显示的语句读取文件,它将无法工作,因为它指示 LOAD DATA 在字段之间查找选项卡:

LOAD DATA INFILE'Data.txt'INTO TABLE table2
  字段由'\ t'终止;

可能的结果是每个输入行将被解释为单个字段。

LOAD DATA 可用于读取从外部源获取的文件。 例如,许多程序可以以逗号分隔值(CSV)格式导出数据,这样行的字段用逗号分隔并用双引号括起来,并带有一行初始的列名。 如果此类文件中的行由回车符/换行符对终止,则此处显示的语句说明了用于加载文件的字段和行处理选项:

LOAD DATA INFILE'data.txt'INTO TABLE tbl_name
  字段由'''封闭''''
  由'\ r \ n'终止的线路
  IGNORE 1 LINES;

如果输入值不一定用引号括起来,请 OPTIONALLY ENCLOSED BY 选项 之前 使用

任何字段或行处理选项都可以指定空字符串( '' )。 如果不为空,则 FIELDS [OPTIONALLY] ENCLOSED BY FIELDS ESCAPED BY 值必须是单个字符。 FIELDS TERMINATED BY LINES STARTING BY LINES TERMINATED BY 值可超过一个字符。 例如,要写入由回车符/换行符对终止的行,或者要读取包含这些行的文件,请指定一个 LINES TERMINATED BY '\r\n' 子句。

要读取包含由组成的行分隔的笑话的文件 %% ,您可以执行此操作

CREATE TABLE笑话
  (INT NOT NOT AUTO_INCREMENT PRIMARY KEY,
  笑话TEXT NOT NULL);
LOAD DATA INFILE'/tmp/jokes.txt'INTO TABLE笑话
  字段被''终止
  由'\ n %% \ n'终止的行(笑话);

FIELDS [OPTIONALLY] ENCLOSED BY 控制字段引用。 对于output( SELECT ... INTO OUTFILE ),如果省略该单词 OPTIONALLY ,则所有字段都由该 ENCLOSED BY 字符 包围 此处显示了此类输出的示例(使用逗号作为字段分隔符):

“1”,“一根弦”,“100.20”
“2”,“包含逗号的字符串”,“102.20”
“3”,“包含”引号“的字符串,”102.20“
“4”,“包含\”的字符串,引号和逗号“,”102.20“

如果指定 OPTIONALLY ENCLOSED BY 字符仅用于从具有字符串数据类型(如柱围值 CHAR BINARY TEXT ,或 ENUM ):

1,“一串”,100.20
2,“包含逗号的字符串”,102.20
3,“包含”引号“的字符串,102.20
4,“包含\”的字符串,引号和逗号“,102.20

ENCLOSED BY 字段值中字符的 出现通过在 字符前加上前缀来转义 ESCAPED BY 此外,如果指定空 ESCAPED BY 值,则可能会无意中生成无法正确读取的输出 LOAD DATA 例如,如果转义字符为空,则刚刚显示的前面的输出将显示如下。 注意第四行中的第二个字段在引号后面包含一个逗号,它(错误地)显示为终止字段:

1,“一串”,100.20
2,“包含逗号的字符串”,102.20
3,“包含”引用“的字符串,102.20
4,“包含”,引号和逗号“的字符串,102.20

对于输入, ENCLOSED BY 字符(如果存在)将从字段值的末尾剥离。 (无论是否 OPTIONALLY 指定, 都是如此 ; OPTIONALLY 对输入解释没有影响。) ENCLOSED BY 字符前面的 ESCAPED BY 字符的出现被解释为当前字段值的一部分。

如果字段以 ENCLOSED BY 字符 开头,则 仅当后跟字段或行 TERMINATED BY 序列时, 才会 将该 字符的实例识别为终止字段值 为了避免歧义, ENCLOSED BY 字段值中字符的 出现 可以加倍并被解释为字符的单个实例。 例如,如果 ENCLOSED BY '"' 指定了 if ,则处理引号,如下所示:

“”大“”老板“ - >”大“老板
“大”老板 - >“大”老板
“”BIG“”老板 - >“”BIG“”老板

FIELDS ESCAPED BY 控制如何读取或写入特殊字符:

  • 对于输入,如果 FIELDS ESCAPED BY 字符不为空,则剥离该字符的出现,并且字面上将后续字符作为字段值的一部分。 一些双字符序列是异常,其中第一个字符是转义字符。 这些序列如下表所示( \ 用于转义字符)。 NULL 处理 规则 将在本节后面介绍。

    字符 逃脱序列
    \0 ASCII NUL( X'00' )字符
    \b 退格字符
    \n 换行符(换行符)
    \r 回车符
    \t 制表符。
    \Z ASCII 26(Control + Z)
    \N 空值

    有关 \ -escape语法的 更多信息 ,请参见 第9.1.1节“字符串文字”

    如果 FIELDS ESCAPED BY 字符为空,则不会发生转义序列解释。

  • 对于输出,如果 FIELDS ESCAPED BY 字符不为空,则用于在输出中为后面的字符添加前缀:

    • 这个 FIELDS ESCAPED BY 角色。

    • 这个 FIELDS [OPTIONALLY] ENCLOSED BY 角色。

    • 如果 字符为空或未指定 ,则为 FIELDS TERMINATED BY LINES TERMINATED BY 的第一个字符 ENCLOSED BY

    • ASCII 0 (转义字符后面实际写入的是ASCII 0 ,而不是零值字节)。

    如果 FIELDS ESCAPED BY 字符是空的,没有字符被转义,并且 NULL 是输出 NULL ,没有 \N 指定空的转义字符可能不是一个好主意,特别是如果数据中的字段值包含刚刚给出的列表中的任何字符。

在某些情况下,现场和线路处理选项相互作用:

  • 如果 LINES TERMINATED BY 是一个空字符串且 FIELDS TERMINATED BY 非空,则行也将终止 FIELDS TERMINATED BY

  • 如果 FIELDS TERMINATED BY FIELDS ENCLOSED BY 值都为空( '' ),则使用固定行(非定界)格式。 对于固定行格式,字段之间不使用分隔符(但您仍然可以使用行终止符)。 相反,使用足够宽的字段宽度来读取和写入列值,以保存字段中的所有值。 TINYINT SMALLINT MEDIUMINT INT ,和 BIGINT ,场宽度是4,6,8,11,和20,分别,不管声明显示宽度是什么。

    LINES TERMINATED BY 仍然用于分隔线。 如果某行不包含所有字段,则其余列将设置为其默认值。 如果您没有行终止符,则应将其设置为 '' 在这种情况下,文本文件必须包含每行的所有字段。

    固定行格式也会影响 NULL 值的 处理 ,如后面所述。

    注意

    如果您使用多字节字符集,则固定大小格式不起作用。

NULL 值的 处理 根据使用的 FIELDS LINES 选项 而有所不同

  • 对于默认值 FIELDS LINES 值, NULL \N 为输出的字段值, \N 并且读取 字段值为 NULL 输入(假设 ESCAPED BY 字符为 \ )。

  • 如果 FIELDS ENCLOSED BY 不为空, 则将 包含文字 NULL 作为其值 的字段 作为值读取 NULL 这与 字符中 NULL 包含 的单词不同 FIELDS ENCLOSED BY ,后者被读作字符串 'NULL'

  • 如果 FIELDS ESCAPED BY 为空, NULL 则写为单词 NULL

  • 使用固定行格式( 在空 FIELDS TERMINATED BY 和时 FIELDS ENCLOSED BY 都使用), NULL 写为空字符串。 这会导致 NULL 表中的值和空字符串在写入文件时无法区分,因为两者都写为空字符串。 如果您在重新读取文件时需要能够区分两者,则不应使用固定行格式。

尝试加载 NULL NOT NULL 列会导致为列的数据类型和警告分配隐式默认值,或者在严格SQL模式下分配错误。 第11.7节“数据类型默认值” 中讨论了隐式默认值

有些情况不受以下方面的支持 LOAD DATA

  • 固定大小的行( FIELDS TERMINATED BY 以及 FIELDS ENCLOSED BY 空的)和/ BLOB TEXT 列。

  • 如果指定一个与另一个相同的分隔符或另一个的前缀, LOAD DATA 则无法正确解释输入。 例如,以下 FIELDS 子句会导致问题:

    字段被''''封闭'''终止
    
  • 如果 FIELDS ESCAPED BY 为空,则包含值的出现 FIELDS ENCLOSED BY LINES TERMINATED BY 后跟 的字段 FIELDS TERMINATED BY 值会导致 LOAD DATA 过早地停止读取字段或行。 发生这种情况是因为 LOAD DATA 无法正确确定字段或行值的结束位置。

列列表规范

以下示例加载表的所有列 persondata

LOAD DATA INFILE'persondata.txt'INTO TABLE persondata;

默认情况下,如果在 LOAD DATA 语句 末尾没有提供列列表 ,则输入行应包含每个表列的字段。 如果只想加载某些表的列,请指定列列表:

LOAD DATA INFILE'persondata.txt'INTO TABLE persondatacol_name_or_user_var[,col_name_or_user_var] ......);

如果输入文件中字段的顺序与表中列的顺序不同,则还必须指定列列表。 否则,MySQL无法告诉如何将输入字段与表列匹配。

输入预处理

每个 col_name_or_user_var 值都是列名或用户变量。 使用用户变量,该 SET 子句使您可以在将结果分配给列之前对其值执行预处理转换。

SET 子句 中的用户变量 可以以多种方式使用。 下面的示例直接使用第一个输入列作为值 t1.column1 ,并将第二个输入列分配给用户变量,该变量在用于以下值之前经过除法运算 t1.column2

LOAD DATA INFILE'file.txt'
  INTO表t1
  (column1,@ var1)
  SET column2 = @ var1 / 100;

SET 子句可用于提供不是从输入文件派生的值。 以下语句设置 column3 为当前日期和时间:

LOAD DATA INFILE'file.txt'
  INTO表t1
  (column1,column2)
  SET column3 = CURRENT_TIMESTAMP;

您还可以通过将输入值分配给用户变量而不将变量分配给表列来丢弃输入值:

LOAD DATA INFILE'file.txt'
  INTO表t1
  (column1,@ dummy,column2,@ dad,column3);

使用列/变量列表和 SET 子句受以下限制:

  • SET 子句中的 赋值 应该只在赋值运算符的左侧有列名。

  • 您可以在 SET 分配 的右侧使用子查询 返回要分配给列的值的子查询可能只是标量子查询。 此外,您不能使用子查询从正在加载的表中进行选择。

  • IGNORE 不会为列/变量列表或 SET 子句 处理子句 忽略的行

  • 加载固定行格式的数据时,无法使用用户变量,因为用户变量没有显示宽度。

处理输入行时, LOAD DATA 将其拆分为字段,并根据列/变量列表和 SET 子句 使用值 (如果存在)。 然后将生成的行插入表中。 如果有 BEFORE INSERT AFTER INSERT 触发器,则分别在插入行之前或之后激活它们。

如果输入行包含太多字段,则会忽略额外字段并增加警告数。

如果输入行的字段太少,则缺少输入字段的表列将设置为其默认值。 第11.7节“数据类型默认值”中 描述了默认值分配

空字段值的解释与缺少的字段不同:

  • 对于字符串类型,该列设置为空字符串。

  • 对于数字类型,列设置为 0

  • 对于日期和时间类型,该列设置 为该类型 的相应 值。 请参见 第11.3节“日期和时间类型”

如果在 INSERT or UPDATE 语句中 显式地将空字符串明确分配给字符串,数字或日期或时间类型,则会产生相同的值

如果将SQL模式设置为限制值,则处理空或不正确的字段值与刚刚描述的不同。 例如,如果 sql_mode 设置为 TRADITIONAL ,则转换空值或值(例如 'x' 数字列)会导致错误,而不是转换为0.(使用 LOCAL 或者 IGNORE ,警告会发生而不是错误,即使有限制 sql_mode 值,使用与非限制性SQL模式相同的最接近值行为插入行。这是因为服务器无法在操作过程中停止传输文件。)

TIMESTAMP 仅当 NULL 值(即, \N )没有声明列允许 NULL 值,或者 TIMESTAMP 列的默认值是当前时间戳并且从字段中省略时, 列才会设置为当前日期和时间 指定字段列表时列出。

LOAD DATA 将所有输入视为字符串,因此您不能像使用 语句 那样使用数值 ENUM SET INSERT 必须将 all ENUM SET 值指定为字符串。

BIT 无法使用二进制表示法直接加载值(例如, b'011010' )。 要解决此问题,请使用该 SET 子句去除前导 b' 和尾随 ' 并执行base-2到base-10转换,以便MySQL BIT 正确地 将值加载到 列中:

外壳> cat /tmp/bit_test.txt
b'10'
b'1111111'
shell> mysql test
mysql>LOAD DATA INFILE '/tmp/bit_test.txt'
       INTO TABLE bit_test (@var1)
       SET b = CAST(CONV(MID(@var1, 3, LENGTH(@var1)-3), 2, 10) AS UNSIGNED);
查询正常,2行受影响(0.00秒)
记录:2删除:0跳过:0警告:0

MySQL的> SELECT BIN(b+0) FROM bit_test;
+ ---------- +
| BIN(b + 0)|
+ ---------- +
| 10 |
| 1111111 |
+ ---------- +
2行(0.00秒)

对于 二进制表示法 BIT 中的 0b 值(例如, 0b011010 ),请使用此 SET 子句去除前导 0b

SET b = CAST(CONV(MID(@ var1,3,LENGTH(@ var1)-2),2,10)AS UNSIGNED)

声明结果信息

LOAD DATA 语句完成,它返回以下格式的信息字符串:

记录:1已删除:0跳过:0警告:0

警告在与使用 INSERT 语句 插入值时相同的情况下发生 (请参见 第13.2.6节“INSERT语法” ),但 LOAD DATA 输入行中字段太少或太多时也会生成警告。

您可以使用 SHOW WARNINGS 获取第一个 max_error_count 警告 的列表 作为有关错误的信息。 请参见 第13.7.6.40节“显示警告语法”

如果您使用的是C API,则可以通过调用该 mysql_info() 函数 来获取有关该语句的信息 请参见 第28.7.7.36节“mysql_info()”

杂项主题

在Unix上,如果需要 LOAD DATA 从管道读取,可以使用以下技术(该示例将 / 目录 列表加载 到表中 db1.t1 ):

mkfifo /mysql/data/db1/ls.dat
chmod 666 /mysql/data/db1/ls.dat
find / -ls> /mysql/data/db1/ls.dat&
mysql -e“LOAD DATA INFILE'ls.dat'INTO TABLE t1”db1

在这里,您必须 在不同的终端上 运行生成要加载的数据和 mysql 命令的命令,或者在后台运行数据生成过程(如上例所示)。 如果不这样做,管道将阻塞,直到 mysql 进程 读取数据

13.2.8 LOAD XML语法

加载XML
    [LOW_PRIORITY | CONCURRENT] [当地]
    INFILE' file_name'
    [REPLACE | 忽视]
    INTO TABLE [ db_name。] tbl_name
    [字符集charset_name]
    [由'< tagname>' 识别的行号]
    [IGNORE number{LINES | ROWS}]
    [(field_name_or_user_var
        [,field_name_or_user_var] ......)]
    [SET col_name= { expr| 默认},
        [,col_name= { expr| DEFAULT}] ...]

LOAD XML 语句将XML文件中的数据读入表中。 file_name 必须作为一个字符串。 所述 tagname 可选的在 ROWS IDENTIFIED BY 条款也必须给予作为文字串,并且必须由尖括号(包围 < > )。

LOAD XML 作为 在XML输出模式下 运行 mysql 客户端 的补充 (即,使用该 --xml 选项 启动客户端 )。 要将表中的数据写入XML文件,可以 使用 系统shell中 选项 调用 mysql 客户端 ,如下所示: --xml -e

外壳> mysql --xml -e 'SELECT * FROM mydb.mytable' > file.xml

要将文件读回表中,请使用 LOAD XML 默认情况下,该 <row> 元素被认为是数据库表行的等价物; 这可以使用该 ROWS IDENTIFIED BY 子句 进行更改

该语句支持三种不同的XML格式:

  • 列名称作为属性,列值作为属性值:

    < =“ =“ ”...... />
    row column1value1column2value2
  • 列名作为标记,列值作为这些标记的内容:

    < row>
      < column1> value1</ column1>
      < column2> value2</ column2>
    </ row>
    
  • 列名是 标记 name 属性 <field> ,值是这些标记的内容:

    <行>
      <field name =' column1'> value1</ field>
      <field name =' column2'> value2</ field>
    </行>
    

    这是其他MySQL工具使用的格式,例如 mysqldump

所有三种格式都可以在同一个XML文件中使用; 导入例程自动检测每行的格式并正确解释它。 根据标记或属性名称和列名称匹配标记。

下列条款基本上是连续工作以同样的方式 LOAD XML ,因为他们对做 LOAD DATA

  • LOW_PRIORITY 要么 CONCURRENT

  • LOCAL

  • REPLACE 要么 IGNORE

  • CHARACTER SET

  • SET

有关这些子句的更多信息 请参见 第13.2.7节“LOAD DATA语法”

(field_name_or_user_var, ...) 是一个或多个以逗号分隔的XML字段或用户变量的列表。 用于此目的的用户变量的名称必须与XML文件中的字段名称匹配,前缀为 @ 您可以使用字段名称仅选择所需的字段。 用户变量可用于存储相应的字段值以供后续重用。

子句使第一 XML文件中的行被跳过。 它类似于 声明的 条款。 IGNORE number LINES IGNORE number ROWS number LOAD DATA IGNORE ... LINES

假设我们有一个名为的表 person ,如下所示:

使用测试;

CREATE TABLE人(
    person_id INT NOT NULL PRIMARY KEY,
    fname VARCHAR(40)NULL,
    lname VARCHAR(40)NULL,
    创造了TIMESTAMP
);

进一步假设该表最初为空。

现在假设我们有一个简单的XML文件 person.xml ,其内容如下所示:

<列表>
  <person person_id =“1”fname =“Kapek”lname =“Sainnouine”/>
  <person person_id =“2”fname =“Sajon”lname =“Rondela”/>
  <person person_id =“3”> <fname> Likame </ fname> <lname>Örrtmons</ lname> </ person>
  <person person_id =“4”> <fname> Slar </ fname> <lname> Manlanth </ lname> </ person>
  <person> <field name =“person_id”> 5 </ field> <field name =“fname”> Stoma </ field>
    <field name =“lname”> Milu </ field> </ person>
  <person> <field name =“person_id”> 6 </ field> <field name =“fname”> Nirtam </ field>
    <field name =“lname”>Sklöd</ field> </ person>
  <person person_id =“7”> <fname> Sungam </ fname> <lname>Dulbåd</ lname> </ person>
  <person person_id =“8”fname =“Sraref”lname =“Encmelt”/>
</列表>

前面讨论的每种允许的XML格式都在此示例文件中表示。

要将数据 person.xml 导入 person 表中,可以使用以下语句:

mysql> LOAD XML LOCAL INFILE 'person.xml'
    - >    INTO TABLE person
    - >   ROWS IDENTIFIED BY '<person>';

查询OK,8行受影响(0.00秒)
记录:8删除:0跳过:0警告:0

在这里,我们假设它 person.xml 位于MySQL数据目录中。 如果找不到该文件,则会出现以下错误:

错误2(HY000):找不到文件'/person.xml'(错误代码:2)

ROWS IDENTIFIED BY '<person>' 子句意味着 <person> XML文件 中的每个 元素被认为等同于要导入数据的表中的行。 在这种情况下,这是 数据库中 person test

从服务器的响应中可以看出,将8行导入 test.person 表中。 这可以通过一个简单的 SELECT 声明 来验证

MySQL的> SELECT * FROM person;
+ ----------- + -------- + ------------ + --------------- ------ +
| person_id | fname | lname | 创建|
+ ----------- + -------- + ------------ + --------------- ------ +
| 1 | Kapek | Sainnouine | 2007-07-13 16:18:47 |
| 2 | Sajon | Rondela | 2007-07-13 16:18:47 |
| 3 | Likame | Örrtmons| 2007-07-13 16:18:47 |
| 4 | Slar | Manlanth | 2007-07-13 16:18:47 |
| 5 | 气孔| Nilu | 2007-07-13 16:18:47 |
| 6 | Nirtam | Sklöd| 2007-07-13 16:18:47 |
| 7 | Sungam | Dulbåd| 2007-07-13 16:18:47 |
| 8 | Sreraf | Encmelt | 2007-07-13 16:18:47 |
+ ----------- + -------- + ------------ + --------------- ------ +
8行(0.00秒)

如本节前面所述,这表明3种允许的XML格式中的任何一种或全部都可以出现在单个文件中并使用 LOAD XML

刚刚显示的导入操作的反转 - 即将MySQL表数据转储到XML文件中 - 可以使用 系统shell中 mysql 客户端 完成 ,如下所示:

shell> mysql --xml -e "SELECT * FROM test.person" > person-dump.xml
shell>cat person-dump.xml
<?xml version =“1.0”?>

<resultset statement =“SELECT * FROM test.person”xmlns:xsi =“http://www.w3.org/2001/XMLSchema-instance”>
  <行>
	<field name =“person_id”> 1 </ field>
	<field name =“fname”> Kapek </ field>
	<field name =“lname”> Sainnouine </ field>
  </行>

  <行>
	<field name =“person_id”> 2 </ field>
	<field name =“fname”> Sajon </ field>
	<field name =“lname”> Rondela </ field>
  </行>

  <行>
	<field name =“person_id”> 3 </ field>
	<field name =“fname”> Likema </ field>
	<field name =“lname”>Örrtmons</ field>
  </行>

  <行>
	<field name =“person_id”> 4 </ field>
	<field name =“fname”> Slar </ field>
	<field name =“lname”> Manlanth </ field>
  </行>

  <行>
	<field name =“person_id”> 5 </ field>
	<field name =“fname”> Stoma </ field>
	<field name =“lname”> Nilu </ field>
  </行>

  <行>
	<field name =“person_id”> 6 </ field>
	<field name =“fname”> Nirtam </ field>
	<field name =“lname”>Sklöd</ field>
  </行>

  <行>
	<field name =“person_id”> 7 </ field>
	<field name =“fname”> Sungam </ field>
	<field name =“lname”>Dulbåd</ field>
  </行>

  <行>
	<field name =“person_id”> 8 </ field>
	<field name =“fname”> Sreraf </ field>
	<field name =“lname”> Encmelt </ field>
  </行>
</结果集>
注意

--xml 选项使 mysql 客户端对其输出使用XML格式; -e 选项使客户端在该选项后立即执行SQL语句。 请参见 第4.5.1节“ mysql - MySQL命令行客户端”

您可以通过创建 person 的副本 并将转储文件导入新表 来验证转储是否有效 ,如下所示:

mysql> USE test;
mysql>CREATE TABLE person2 LIKE person;
查询正常,0行受影响(0.00秒)

mysql> LOAD XML LOCAL INFILE 'person-dump.xml'
    - >   INTO TABLE person2;
查询OK,8行受影响(0.01秒)
记录:8删除:0跳过:0警告:0

MySQL的> SELECT * FROM person2;
+ ----------- + -------- + ------------ + --------------- ------ +
| person_id | fname | lname | 创建|
+ ----------- + -------- + ------------ + --------------- ------ +
| 1 | Kapek | Sainnouine | 2007-07-13 16:18:47 |
| 2 | Sajon | Rondela | 2007-07-13 16:18:47 |
| 3 | Likema | Örrtmons| 2007-07-13 16:18:47 |
| 4 | Slar | Manlanth | 2007-07-13 16:18:47 |
| 5 | 气孔| Nilu | 2007-07-13 16:18:47 |
| 6 | Nirtam | Sklöd| 2007-07-13 16:18:47 |
| 7 | Sungam | Dulbåd| 2007-07-13 16:18:47 |
| 8 | Sreraf | Encmelt | 2007-07-13 16:18:47 |
+ ----------- + -------- + ------------ + --------------- ------ +
8行(0.00秒)

不要求XML文件中的每个字段都与相应表中的列匹配。 跳过没有相应列的字段。 您可以通过首先清空 person2 表并删除 created 列,然后使用 LOAD XML 我们之前 使用的相同 语句 来看到这一点 ,如下所示:

MySQL的> TRUNCATE person2;
查询OK,8行受影响(0.26秒)

MySQL的> ALTER TABLE person2 DROP COLUMN created;
查询OK,0行受影响(0.52秒)
记录:0重复:0警告:0

MySQL的> SHOW CREATE TABLE person2\G
*************************** 1。排******************** *******
       表:person2
创建表:CREATE TABLE`person2`(
  `person_id` int(11)NOT NULL,
  `fname` varchar(40)DEFAULT NULL,
  `lname` varchar(40)DEFAULT NULL,
  主键(`person_id`)
)ENGINE = InnoDB DEFAULT CHARSET = utf8
1排(0.00秒)

mysql> LOAD XML LOCAL INFILE 'person-dump.xml'
    - >   INTO TABLE person2;
查询OK,8行受影响(0.01秒)
记录:8删除:0跳过:0警告:0

MySQL的> SELECT * FROM person2;
+ ----------- + -------- + ------------ +
| person_id | fname | lname |
+ ----------- + -------- + ------------ +
| 1 | Kapek | Sainnouine |
| 2 | Sajon | Rondela |
| 3 | Likema | Örrtmons|
| 4 | Slar | Manlanth |
| 5 | 气孔| Nilu |
| 6 | Nirtam | Sklöd|
| 7 | Sungam | Dulbåd|
| 8 | Sreraf | Encmelt |
+ ----------- + -------- + ------------ +
8行(0.00秒)

在XML文件的每一行中给出字段的顺序不会影响操作 LOAD XML ; 字段顺序可以在行之间变化,并且不需要与表中的相应列具有相同的顺序。

如前所述,您可以使用 一个或多个XML字段 列表(仅选择所需的字段)或用户变量(以存储相应的字段值供以后使用)。 当您希望将XML文件中的数据插入名称与XML字段名称不匹配的表列时,用户变量尤其有用。 要查看其工作原理,我们首先创建一个名为 的结构与 的结构相匹配的 表,但其列的名称不同: (field_name_or_user_var, ...) individual person

mysql> CREATE TABLE individual (
    - >      individual_id INT NOT NULL PRIMARY KEY,
    - >      name1 VARCHAR(40) NULL,
    - >      name2 VARCHAR(40) NULL,
    - >     made TIMESTAMP
    - >);
查询OK,0行受影响(0.42秒)

在这种情况下,您不能简单地将XML文件直接加载到表中,因为字段和列名称不匹配:

MySQL的> LOAD XML INFILE '../bin/person-dump.xml' INTO TABLE test.individual;
ERROR 1263(22004):列设置为默认值; NULL提供给第1行的NOT NULL列'individual_id'

发生这种情况是因为MySQL服务器查找与目标表的列名匹配的字段名称。 您可以通过在用户变量中选择字段值,然后使用目标表的列设置等于这些变量的值来解决此问题 SET 您可以在单个语句中执行这两个操作,如下所示:

mysql> LOAD XML INFILE '../bin/person-dump.xml'
    - >      INTO TABLE test.individual (@person_id, @fname, @lname, @created)
    - >     SET individual_id=@person_id, name1=@fname, name2=@lname, made=@created;
查询OK,8行受影响(0.05秒)
记录:8删除:0跳过:0警告:0

MySQL的> SELECT * FROM individual;
+ --------------- + -------- + ------------ + ----------- ---------- +
| individual_id | name1 | name2 | 制作|
+ --------------- + -------- + ------------ + ----------- ---------- +
| 1 | Kapek | Sainnouine | 2007-07-13 16:18:47 |
| 2 | Sajon | Rondela | 2007-07-13 16:18:47 |
| 3 | Likema | Örrtmons| 2007-07-13 16:18:47 |
| 4 | Slar | Manlanth | 2007-07-13 16:18:47 |
| 5 | 气孔| Nilu | 2007-07-13 16:18:47 |
| 6 | Nirtam | Sklöd| 2007-07-13 16:18:47 |
| 7 | Sungam | Dulbåd| 2007-07-13 16:18:47 |
| 8 | Srraf | Encmelt | 2007-07-13 16:18:47 |
+ --------------- + -------- + ------------ + ----------- ---------- +
8行(0.00秒)

用户变量的名称 必须 与XML文件中相应字段 的名称相 匹配,并添加必需的 @ 前缀以指示它们是变量。 不需要以与相应字段相同的顺序列出或分配用户变量。

使用 子句,可以将同一XML文件中的数据导入具有不同定义的数据库表中。 对于此示例,假设您有一个名为 包含以下XML 的文件 ROWS IDENTIFIED BY '<tagname>' address.xml

<?xml version =“1.0”?>

<列表>
  <person person_id =“1”>
    <FNAME>罗伯特</ FNAME>
    <L-NAME>琼斯</ L-NAME>
    <address address_id =“1”street =“Mill Creek Road”zip =“45365”city =“Sidney”/>
    <address address_id =“2”street =“Main Street”zip =“28681”city =“Taylorsville”/>
  </人>

  <person person_id =“2”>
    <FNAME>玛丽</ FNAME>
    <L-NAME>史密斯</ L-NAME>
    <address address_id =“3”street =“River Road”zip =“80239”city =“Denver”/>
    <! -  <address address_id =“4”street =“North Street”zip =“37920”city =“Knoxville”/>  - >
  </人>

</列表>

test.person 在清除表中的所有现有记录并显示其结构后, 您可以再次使用 本节前面定义的表,如下所示:

MySQL的< TRUNCATE person;
查询正常,0行受影响(0.04秒)

MySQL的< SHOW CREATE TABLE person\G
*************************** 1。排******************** *******
       表:人
创建表:CREATE TABLE`person`(
  `person_id` int(11)NOT NULL,
  `fname` varchar(40)DEFAULT NULL,
  `lname` varchar(40)DEFAULT NULL,
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  主键(`person_id`)
)ENGINE = MyISAM DEFAULT CHARSET = utf8mb4
1排(0.00秒)

现在 使用以下 语句 address test 数据库中 创建一个 CREATE TABLE

CREATE TABLE地址(
    address_id INT NOT NULL PRIMARY KEY,
    person_id INT NULL,
    street VARCHAR(40)NULL,
    zip INT NULL,
    city VARCHAR(40)NULL,
    创造了TIMESTAMP
);

要将XML文件中的数据导入 person 表中,请执行以下 LOAD XML 语句,该语句指定要由 <person> 元素 指定行 ,如此处所示;

mysql> LOAD XML LOCAL INFILE 'address.xml'
    - >    INTO TABLE person
    - >   ROWS IDENTIFIED BY '<person>';
查询正常,2行受影响(0.00秒)
记录:2删除:0跳过:0警告:0

您可以使用 SELECT 语句 验证是否已导入记录

MySQL的> SELECT * FROM person;
+ ----------- + -------- + ------- + -------------------- -  +
| person_id | fname | lname | 创建|
+ ----------- + -------- + ------- + -------------------- -  +
| 1 | 罗伯特| 琼斯| 2007-07-24 17:37:06 |
| 2 | 玛丽| 史密斯| 2007-07-24 17:37:06 |
+ ----------- + -------- + ------- + -------------------- -  +
2行(0.00秒)

由于 <address> XML文件中 元素在表中没有对应的列 person ,因此会跳过它们。

要将 <address> 元素中 的数据导入 address 表中,请使用 LOAD XML 此处显示 语句:

mysql> LOAD XML LOCAL INFILE 'address.xml'
    - >    INTO TABLE address
    - >   ROWS IDENTIFIED BY '<address>';
查询OK,3行受影响(0.00秒)
记录:3删除:0跳过:0警告:0

您可以看到使用如下 SELECT 语句 导入数据

MySQL的> SELECT * FROM address;
+ ------------ + ----------- + ----------------- + ------ -  + -------------- + --------------------- +
| address_id | person_id | 街道| zip | 城市| 创建|
+ ------------ + ----------- + ----------------- + ------ -  + -------------- + --------------------- +
| 1 | 1 | Mill Creek Road | 45365 | 西德尼| 2007-07-24 17:37:37 |
| 2 | 1 | 主街| 28681 | 泰勒斯维尔| 2007-07-24 17:37:37 |
| 3 | 2 | 河道| 80239 | 丹佛| 2007-07-24 17:37:37 |
+ ------------ + ----------- + ----------------- + ------ -  + -------------- + --------------------- +
3组(0.00秒)

<address> 不会导入XML注释中包含 元素 的数据 然而,由于有一个 person_id 在列 address 表中,值 person_id 从父属性 <person> 的每个元素 <address> 导入到 address 表中。

安全考虑因素。  与该 LOAD DATA 语句一样,XML文件从客户端主机到服务器主机的传输由MySQL服务器启动。 理论上,可以构建修补的服务器,该服务器将告诉客户端程序传输服务器选择的文件而不是 LOAD XML 语句中 客户端指定的文件 这样的服务器可以访问客户端用户具有读访问权限的客户端主机上的任何文件。

在Web环境中,客户端通常从Web服务器连接到MySQL。 可以对MySQL服务器运行任何命令的用户可以 LOAD XML LOCAL 用来读取Web服务器进程具有读访问权限的任何文件。 在此环境中,与MySQL服务器相关的客户端实际上是Web服务器,而不是由连接到Web服务器的用户运行的远程程序。

您可以通过使用 --local-infile=0 启动服务器来禁用从客户端加载XML文件 --local-infile=OFF 启动 mysql 客户端以 LOAD XML 在客户端会话期间 禁用 此选项也可以使用

要防止客户端从服务器加载XML文件,请不要将 FILE 权限 授予 相应的MySQL用户帐户,或者如果客户端用户帐户已拥有该权限,则撤消此权限。

重要

撤销 FILE 只能从执行权限(或没有在第一时间给予它)让用户 LOAD XML 声明(还有 LOAD_FILE() 功能;它并 不能 阻止用户执行 LOAD XML LOCAL 。要禁止这种说法,你必须启动服务器或客户端与 --local-infile=OFF

换句话说,该 FILE 权限仅影响客户端是否可以读取服务器上的文件; 它与客户端是否可以读取本地文件系统上的文件无关。

对于使用使用表锁的存储引擎的分区表,例如 MyISAM ,由 LOAD XML 表的所​​有分区上的执行锁 引起的任何锁 这不适用于使用采用行级锁定的存储引擎的表,例如 InnoDB 有关更多信息,请参阅 分区和锁定

13.2.9 REPLACE语法

REPLACE [LOW_PRIORITY | 延迟]
    [INTO] tbl_name
    [PARTITION(partition_name[,partition_name ] ...)]
    [(col_name[,col_name] ......)]
    {VALUES | VALUE}(value_list)[,(value_list)] ......

REPLACE [LOW_PRIORITY | 延迟]
    [INTO] tbl_name
    [PARTITION(partition_name[,partition_name ] ...)]assignment_list

REPLACE [LOW_PRIORITY | 延迟]
    [INTO] tbl_name
    [PARTITION(partition_name[,partition_name ] ...)]
    [(col_name[,col_name] ......)]
    选择 ...

value
    { expr| 默认}

value_listvalue[,value] ......

assignmentcol_name=value

assignment_listassignment[,assignment] ......

REPLACE 与此类似 INSERT ,除非表中的旧行与a PRIMARY KEY UNIQUE 索引 的新行具有相同的值, 否则 在插入新行之前将删除旧行。 请参见 第13.2.6节“INSERT语法”

REPLACE 是SQL标准的MySQL扩展。 它可以插入, 删除 和插入。 对于标准SQL的另一个MySQL扩展 - 插入或 更新 - 请 参见第13.2.6.2节“INSERT ... ON DUPLICATE KEY UPDATE语法”

DELAYED MySQL 5.6中不推荐使用插入和替换。 在MySQL 8.0中, DELAYED 不受支持。 服务器识别但忽略 DELAYED 关键字,将替换作为非延迟替换处理,并生成 ER_WARN_LEGACY_SYNTAX_CONVERTED 警告。 不再支持REPLACE DELAYED。语句已转换为REPLACE。 DELAYED 关键字将在以后的版本中删除。

注意

REPLACE 只有当一个表有一个 PRIMARY KEY 一个 UNIQUE 索引 时才有意义 否则,它等同于 INSERT ,因为没有索引可用于确定新行是否与另一行重复。

所有列的值都取自 REPLACE 语句中 指定的值 任何缺少的列都设置为默认值,就像发生的那样 INSERT 您不能引用当前行中的值并在新行中使用它们。 如果使用诸如的赋值 ,则对右侧列名的引用将被视为 ,因此赋值等效于 SET col_name = col_name + 1 DEFAULT(col_name) SET col_name = DEFAULT(col_name) + 1

要使用 REPLACE ,您必须拥有 表的权限 INSERT DELETE 权限。

如果显式替换生成的列,则唯一允许的值为 DEFAULT 有关生成的列的信息,请参见 第13.1.20.9节“创建表和生成的列”

REPLACE 支持使用 PARTITION 带有分区,子分区或两者的逗号分隔名称列表 关键字进行 显式分区选择 与此同时 INSERT ,如果无法将新行插入任何这些分区或子分区,则 REPLACE 语句将失败,并显示错误“ 找到与给定分区集不匹配的行” 有关更多信息和示例,请参见 第23.5节“分区选择”

REPLACE 语句返回一个计数以指示受影响的行数。 这是删除和插入的行的总和。 如果单行的计数为1, REPLACE 则插入一行并且不删除任何行。 如果计数大于1,则在插入新行之前删除一个或多个旧行。 如果表包含多个唯一索引,并且新行为不同唯一索引中的不同旧行重复值,则单行可以替换多个旧行。

受影响的行数使得可以轻松确定是 REPLACE 仅添加了行还是替换了任何行:检查计数是1(已添加)还是更高(已替换)。

如果您使用的是C API,则可以使用该 mysql_affected_rows() 函数 获取受影响的行数

您无法替换为表并从子查询中的同一表中进行选择。

MySQL对 REPLACE (和 LOAD DATA ... REPLACE 使用以下算法

  1. 尝试将新行插入表中

  2. 插入失败,因为主键或唯一索引发生重复键错误:

    1. 从表中删除具有重复键值的冲突行

    2. 再次尝试将新行插入表中

在重复键错误的情况下,存储引擎可能执行 REPLACE 更新而不是删除加插入,但语义是相同的。 除了存储引擎增加 状态变量 的可能差异之外,没有用户可见的效果 Handler_xxx

因为 REPLACE ... SELECT 语句 的结果 取决于来自的行的顺序, SELECT 并且不能总是保证这个顺序,所以当记录这些语句以使主服务器和从服务器发散时,可能是这样。 因此, REPLACE ... SELECT 语句被标记为基于语句的复制不安全。 当使用基于语句的模式时,此类语句在错误日志中生成警告,并在使用 MIXED 模式 时使用基于行的格式写入二进制日志 另请参见 第17.2.1.1节“基于语句和基于行的复制的优点和缺点”

修改未分区以适应分区的现有表时,或者在修改已分区表的分区时,可以考虑更改表的主键(请参见 第23.6.1节“分区键,主键和唯一键”) “ )。 您应该知道,如果这样做, REPLACE 语句 的结果 可能会受到影响,就像您修改非分区表的主键一样。 考虑以下 CREATE TABLE 语句 创建的表

CREATE TABLE测试(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  data VARCHAR(64)DEFAULT NULL,
  ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY(id)
);

当我们创建这个表并运行mysql客户端中显示的语句时,结果如下:

MySQL的> REPLACE INTO test VALUES (1, 'Old', '2014-08-20 18:47:00');
查询正常,1行受影响(0.04秒)

MySQL的> REPLACE INTO test VALUES (1, 'New', '2014-08-20 18:47:42');
查询OK,2行受影响(0.04秒)

MySQL的> SELECT * FROM test;
+ ---- + ------ + --------------------- +
| id | 数据| ts |
+ ---- + ------ + --------------------- +
| 1 | 新的| 2014-08-20 18:47:42 |
+ ---- + ------ + --------------------- +
1排(0.00秒)

现在我们创建一个几乎与第一个表相同的第二个表,除了主键现在覆盖2列,如此处所示(强调文本):

CREATE TABLE test2(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  data VARCHAR(64)DEFAULT NULL,
  ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY(id,ts)
);

当我们 在原始 运行 test2 相同的两个 REPLACE 语句时 test ,我们获得了不同的结果:

MySQL的> REPLACE INTO test2 VALUES (1, 'Old', '2014-08-20 18:47:00');
查询OK,1行受影响(0.05秒)

MySQL的> REPLACE INTO test2 VALUES (1, 'New', '2014-08-20 18:47:42');
查询正常,1行受影响(0.06秒)

MySQL的> SELECT * FROM test2;
+ ---- + ------ + --------------------- +
| id | 数据| ts |
+ ---- + ------ + --------------------- +
| 1 | 老| 2014-08-20 18:47:00 |
| 1 | 新的| 2014-08-20 18:47:42 |
+ ---- + ------ + --------------------- +
2行(0.00秒)

这是因为,当运行时 test2 id ts 值必须匹配要替换的行的现有行的值; 否则,插入一行。

REPLACE 使用存储引擎例如影响分区表声明 MyISAM 了采用表级锁锁只有那些含有匹配的行的分区 REPLACE 声明 WHERE 子句,只要没有表分区的列被更新; 否则整个表都被锁定。 (对于 InnoDB 使用行级锁定的 存储引擎 ,不会发生分区锁定。)有关更多信息,请参阅 分区和锁定

13.2.10 SELECT语法

选择
    [全部| DISTINCT | DISTINCTROW]
      [HIGH_PRIORITY]
      [STRAIGHT_JOIN]
      [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
      [SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
    select_expr [, select_expr ...]
    [来自table_references
      [PARTITIONpartition_list ]
    [哪里 where_condition]
    [GROUP BY { col_name| expr|position},... [WITH ROLLUP]]
    [HAVING where_condition ]
    [WINDOW window_nameAS(window_spec
        [,window_nameAS(window_spec)] ...]
    [ORDER BY { col_name| expr|position}
      [ASC | DESC],... [与ROLLUP]]
    [LIMIT {[ offset,] row_count| row_countOFFSEToffset }]
    [INTO OUTFILE'file_name '
        [字符集charset_name]
         export_options
      | INTO DUMPFILE'file_name '
      | INTO var_name[,var_name ]]
    [FOR {更新| 分享} [OF tbl_name[,tbl_name] ...] [NOWAIT | SKIP LOCKED]
      | 锁定共享模式]]

SELECT 用于检索从一个或多个表中选择的行,并且可以包括 UNION 语句和子查询。 请参见 第13.2.10.3节“UNION语法” 第13.2.11节“子查询语法” 一个 SELECT 语句可以用开始 WITH 子句来定义内访问的公共表表达式 SELECT 请参见 第13.2.13节“WITH语法(公用表表达式)”

最常用的 SELECT 陈述 条款 是:

  • 每个都 select_expr 表示要检索的列。 必须至少有一个 select_expr

  • table_references 表示从中检索行的一个或多个表。 其语法在 第13.2.10.2节“JOIN语法”中描述

  • SELECT 支持使用 PARTITION 带有一个分区列表或子分区(或两者)的 显式分区选择 ,这些分区或子分区位于a的表名后面 table_reference (参见 第13.2.10.2节“JOIN语法” )。 在这种情况下,仅从列出的分区中选择行,并忽略表的任何其他分区。 有关更多信息和示例,请参见 第23.5节“分区选择”

    SELECT ... PARTITION 从使用存储引擎的 MyISAM 表中执行表级锁(以及分区锁)仅锁定该 PARTITION 选项 指定的分区或子分区

    有关更多信息,请参阅 分区和锁定

  • WHERE 如果给出 子句,则表示行必须满足要选择的条件。 where_condition 是一个表达式,对于要选择的每一行,计算结果为true。 如果没有 WHERE 子句, 该语句将选择所有行

    WHERE 表达式中,您可以使用MySQL支持的任何函数和运算符,但聚合(汇总)函数除外。 请参见 第9.5节“表达式” 第12章 函数和运算符”

SELECT 也可用于检索计算的行而不引用任何表。

例如:

MySQL的> SELECT 1 + 1;
        - > 2

DUAL 在没有引用表的情况下, 您可以指定 为虚拟表名:

MySQL的> SELECT 1 + 1 FROM DUAL;
        - > 2

DUAL 纯粹是为了方便那些要求所有 SELECT 陈述应该具有的人 FROM 以及可能的其他条款。 MySQL可能会忽略这些子句。 FROM DUAL 如果没有引用表, MySQL不需要

通常,使用的子句必须完全按照语法描述中显示的顺序给出。 例如,一个 HAVING 条款必须在任何 GROUP BY 条款之后和任何 ORDER BY 条款 之前 例外情况是该 INTO 子句可以如语法描述中所示出现,也可以紧接在 select_expr 列表 后面出现 有关更多信息 INTO ,请参见 第13.2.10.1节“SELECT ... INTO语法”

select_expr 术语 列表 包括指示要检索哪些列的选择列表。 术语指定列或表达式或可以使用 * -shorthand:

  • 仅包含单个非限定条件的选择列表 * 可用作从所有表中选择所有列的简写:

    SELECT * FROM t1 INNER JOIN t2 ...
    
  • tbl_name.* 可以用作合格的速记来选择命名表中的所有列:

    SELECT t1。*,t2。* FROM t1 INNER JOIN t2 ...
    
  • * 在选择列表中 使用不合格 的其他项可能会产生解析错误。 要避免此问题,请使用限定 tbl_name.* 参考

    SELECT AVG(得分),t1。* FROM t1 ...
    

以下列表提供了有关其他 SELECT 子句的 其他信息

  • A select_expr 可以使用别名 别名用作表达式的列名,并且可以在被使用 条款。 例如: AS alias_name GROUP BY ORDER BY HAVING

    SELECT CONCAT(last_name,',',first_name)AS full_name
      FROM mytable ORDER BY full_name;
    

    使用标识符 AS 别名化时 关键字是可选 select_expr 的。 前面的例子可能是这样编写的:

    SELECT CONCAT(last_name,',',first_name)full_name
      FROM mytable ORDER BY full_name;
    

    但是,因为它 AS 是可选的,如果您忘记两个 select_expr 表达式 之间的逗号,则会出现一个微妙的问题 :MySQL将第二个解释为别名。 例如,在以下语句中, columnb 将被视为别名:

    SELECT columna columnb FROM mytable;
    

    因此, AS 在指定列别名时 习惯 明确 使用是一种好习惯

    不允许在 WHERE 子句中 引用列别名 ,因为在 WHERE 执行子句 时可能尚未确定列值 请参见 第B.4.4.4节“列别名的问题”

  • 子句指示要从中检索行的一个或多个表。 如果您为多个表命名,则表示您正在执行连接。 有关连接语法的信息,请参见 第13.2.10.2节“JOIN语法” 对于指定的每个表,您可以选择指定别名。 FROM table_references

    tbl_name[[AS] alias] [ index_hint]
    

    索引提示的使用为优化器提供了有关如何在查询处理期间选择索引的信息。 有关指定这些提示的语法的说明,请参见 第8.9.4节“索引提示”

    您可以使用 另一种方法强制MySQL更喜欢键扫描而不是表扫描。 请参见 第5.1.8节“服务器系统变量” SET max_seeks_for_key=value

  • 您可以将默认数据库中的表称为 tbl_name db_name tbl_name 明确指定数据库。 您可以将列引用为 col_name tbl_name col_name 或者 db_name tbl_name col_name 您无需指定 tbl_name db_name tbl_name 列引用的前缀,除非引用不明确。 有关 需要更明确的列引用形式的歧义的示例, 请参见 第9.2.1节“标识符限定符”

  • 表引用可以使用 别名 这些陈述是等价的: tbl_name AS alias_name tbl_name alias_name

    SELECT t1.name,t2.salary FROM employee AS t1,info AS t2
      WHERE t1.name = t2.name;
    
    SELECT t1.name,t2.salary FROM employee t1,info t2
      WHERE t1.name = t2.name;
    
  • 可以 使用列名,列别名或列位置 ORDER BY GROUP BY 子句中 引用为输出选择的 列。 列位置是整数,以1开头:

    选择大学,地区,种子来自锦标赛
      ORDER BY地区,种子;
    
    选择大学,地区AS r,种子AS s FROM锦标赛
      ORDER BY r,s;
    
    选择大学,地区,种子来自锦标赛
      订购2,3;
    

    要按相反顺序排序,请将 DESC (descending)关键字 添加到要排序 ORDER BY 子句中 列的名称 默认为升序; 这可以使用 ASC 关键字 明确指定

    如果 ORDER BY 在子查询中发生并且也在外部查询中应用,则最外层 ORDER BY 优先。 例如,以下语句的结果按降序排序,而不是按升序排序:

    (选择......由a命令)由DESC命令;
    

    不推荐使用列位置,因为已从SQL标准中删除了语法。

  • 在MySQL 8.0.13之前,MySQL支持允许显式的非标准语法扩展 ASC 列的 DESC 指定 GROUP BY MySQL 8.0.12及更高版本支持 ORDER BY 分组功能,因此不再需要使用此扩展。 (Bug#86312,Bug#26073525)这也意味着您可以在使用时对任意一列或多列进行排序 GROUP BY ,如下所示:

    SELECT a,b,COUNT(c)AS t FROM test_table GROUP BY a,b ORDER BY a,t DESC;
    

    从MySQL 8.0.13开始, GROUP BY 不再支持扩展: ASC 或者是 DESC 指示符 GROUP BY 不允许 列的

  • 当您使用 ORDER BY GROUP BY 对列中的列进行排序时 SELECT ,服务器仅使用 max_sort_length 系统变量 指示的初始字节数对值进行排序

  • MySQL扩展了使用 GROUP BY 以允许选择 GROUP BY 子句 中未提及的字段 如果你没有得到你从你的查询所期望的结果,请阅读的描述 GROUP BY 中发现的 第12.20,“集合(GROUP BY)功能”

  • GROUP BY 允许 WITH ROLLUP 修饰符。 请参见 第12.20.2节“GROUP BY Modifiers”

    以前,不允许 ORDER BY 在具有 WITH ROLLUP 修饰符 的查询中 使用 从MySQL 8.0.12开始,此限制被取消。 请参见 第12.20.2节“GROUP BY Modifiers”

  • HAVING 条款几乎在最后一次应用,就在项目发送到客户端之前,没有优化。 LIMIT 之后适用 HAVING 。)

    SQL标准要求 HAVING 必须仅引用 GROUP BY 聚合函数中使用 子句中的列。 但是,MySQL支持对此行为的扩展,并允许 HAVING 引用 SELECT 列表 中的 列和外部子查询中的列。

    如果 HAVING 子句引用不明确的列,则会发出警告。 在下面的语句中, col2 它是不明确的,因为它既用作别名又用作列名:

    SELECT COUNT(col1)AS col2 FROM t GROUP BY col2 HAVING col2 = 2;
    

    优先考虑标准SQL行为,因此如果 在输出列列表 HAVING GROUP BY 和作为别 名列使用列名,则会 优先选择列中的 GROUP BY 列。

  • 不要 HAVING 用于应该在该 WHERE 条款中的项目。 例如,不要写下面的内容:

    SELECT col_nameFROM tbl_nameHAVING col_name> 0;
    

    写这个:

    SELECT col_nameFROM tbl_nameWHERE col_name> 0;
    
  • HAVING 子句可以引用聚合函数,该 WHERE 子句不能:

    SELECT用户,MAX(薪水)FROM用户
      GROUP BY用户HAVING MAX(薪水)> 10;
    

    (这在一些旧版本的MySQL中不起作用。)

  • MySQL允许重复的列名。 也就是说,可以有多个 select_expr 具有相同名称的。 这是标准SQL的扩展。 因为MySQL也允许 GROUP BY HAVING 引用 select_expr 值,这可能会导致歧义:

    SELECT 12 AS a,FROM t GROUP BY a;
    

    在该语句中,两列都有名称 a 要确保使用正确的列进行分组,请为每个列使用不同的名称 select_expr

  • WINDOW 子句(如果存在)定义了可由窗口函数引用的命名窗口。 有关详细信息,请参见 第12.21.4节“命名Windows”

  • MySQL ORDER BY 通过搜索 select_expr 值,然后在 FROM 子句 中的表的列中 搜索子句中的 非限定列或别名引用 对于 GROUP BY or HAVING 子句,它 FROM 在搜索 select_expr 之前搜索子句 (对于 GROUP BY HAVING ,这与使用相同规则的MySQL 5.0之前的行为不同 ORDER BY 。)

  • LIMIT 子句可用于约束 SELECT 语句 返回的行数 LIMIT 取一个或两个数字参数,它们都必须是非负整数常量,但有以下例外:

    • 在预准备语句中, LIMIT 可以使用 ? 占位符标记 指定参数

    • 在存储的程序中, LIMIT 可以使用整数值例程参数或局部变量来指定参数。

    使用两个参数,第一个参数指定要返回的第一行的偏移量,第二个参数指定要返回的最大行数。 初始行的偏移量为0(不是1):

    SELECT * FROM tbl LIMIT 5,10; #检索行6-15
    

    要从特定偏移量检索所有行直到结果集的末尾,可以使用一些大数字作为第二个参数。 此语句检索从第96行到最后一行的所有行:

    SELECT * FROM tbl LIMIT 95,18446744073709551615;
    

    使用一个参数,该值指定从结果集的开头返回的行数:

    SELECT * FROM tbl LIMIT 5; #检索前5行
    

    换句话说, 相当于 LIMIT row_count LIMIT 0, row_count

    对于预准备语句,您可以使用占位符。 以下语句将从 tbl 表中 返回一行

    SET @ a = 1;
    从'SELECT * FROM tbl LIMIT'中预备STMT?
    使用@a执行STMT;
    

    以下语句将返回表中的第二行到第六行 tbl

    SET @ skip = 1; SET @ numrows = 5;
    准备STMT从'SELECT * FROM tbl LIMIT?,?';
    使用@skip执行STMT,@ numrows;
    

    为了与PostgreSQL兼容,MySQL还支持 语法。 LIMIT row_count OFFSET offset

    如果 LIMIT 在子查询中发生并且也在外部查询中应用,则最外层 LIMIT 优先。 例如,以下语句生成两行,而不是一行:

    (SELECT ... LIMIT 1)LIMIT 2;
    
  • 这种 SELECT ... INTO 形式 SELECT 使查询结果能够写入文件或存储在变量中。 有关更多信息,请参见 第13.2.10.1节“SELECT ... INTO语法”

  • 如果使用 FOR UPDATE 使用页锁或行锁的存储引擎,则查询检查的行将被写入锁定,直到当前事务结束。

    您不能将其 FOR UPDATE 用作 SELECT 声明中的 一部分 (如果您尝试这样做,则该语句将被拒绝并显示错误 无法更新表' ' 正在创建 ' ' 。) CREATE TABLE new_table SELECT ... FROM old_table ... old_table new_table

    FOR SHARE LOCK IN SHARE MODE 设置共享锁,允许其他事务读取已检查的行,但不允许更新或删除它们。 FOR SHARE 并且 LOCK IN SHARE MODE 是等价的。 然而 FOR SHARE ,喜欢 FOR UPDATE ,支持 NOWAIT SKIP LOCKED 选项。 是替代 ,但 仍可用于向后兼容。 OF tbl_name FOR SHARE LOCK IN SHARE MODE LOCK IN SHARE MODE

    NOWAIT 导致 FOR UPDATE FOR SHARE 查询立即执行,如果由于另一个事务持有的锁而无法获得行锁,则返回错误。

    SKIP LOCKED 导致 FOR UPDATE FOR SHARE 查询立即执行,排除结果集中由另一个事务锁定的行。

    NOWAIT SKIP LOCKED 选项对于基于语句的复制是不安全的。

    注意

    跳过锁定行的查询会返回数据的不一致视图。 SKIP LOCKED 因此不适合一般交易工作。 但是,当多个会话访问同一个类似队列的表时,它可用于避免锁争用。

    OF tbl_name 对命名表 应用 FOR UPDATE FOR SHARE 查询。 例如:

    SELECT * FROM t1,t2 for tARE for t1 for update of t2;              
    

    省略 时,查询块引用的所有表都将被锁定 因此,使用不 与另一个锁定子句组合的锁定子句会返回错误。 在多个锁定子句中指定相同的表会返回错误。 如果在 语句 中将别名指定为表名,则 锁定子句只能使用别名。 如果 语句未明确指定别名,则锁定子句只能指定实际的表名。 OF tbl_name OF tbl_name SELECT SELECT

    有关详细信息 FOR UPDATE ,并 FOR SHARE 请参见 第15.7.2.4,“锁定读” 有关 NOWAIT SKIP LOCKED 选项的 其他信息 ,请 参阅使用NOWAIT和SKIP LOCKED锁定读取并发

SELECT 关键字之后,您可以使用许多影响语句操作的修饰符。 HIGH_PRIORITY STRAIGHT_JOIN ,以及开头的修饰符 SQL_ 是标准SQL的MySQL扩展。

  • ALL DISTINCT 修饰符指定重复行是否应该返回。 ALL (默认值)指定应返回所有匹配的行,包括重复行。 DISTINCT 指定从结果集中删除重复的行。 指定两个修饰符是错误的。 DISTINCTROW 是...的同义词 DISTINCT

    在MySQL 8.0.12及更高版本中, DISTINCT 可以与也使用的查询一起使用 WITH ROLLUP (Bug#87450,Bug#26640100)

  • HIGH_PRIORITY SELECT 比更新表的语句 提供 更高的优先级。 您应该仅将此用于非常快速且必须立即执行的查询。 SELECT HIGH_PRIORITY 在表被锁定以进行读取时发出 查询即使存在等待表空闲的更新语句也会运行。 这会影响只使用表级锁只存储引擎(例如 MyISAM MEMORY MERGE )。

    HIGH_PRIORITY 不能与 SELECT 作为a的一部分的语句 一起使用 UNION

  • STRAIGHT_JOIN 强制优化器按照 FROM 子句 中列出的顺序连接表 如果优化程序以非最佳顺序连接表,则可以使用此方法加速查询。 STRAIGHT_JOIN 也可以在 table_references 列表中使用。 请参见 第13.2.10.2节“JOIN语法”

    STRAIGHT_JOIN 不适用于优化程序视为 const system 表的 任何 表。 这样的表生成单行,在查询执行的优化阶段读取,并且在查询执行进行之前用适当的列值替换对其列的引用。 这些表将首先显示在显示的查询计划中 EXPLAIN 请参见 第8.8.1节“使用EXPLAIN优化查询” 此异常可能不适用于 const system 那些在使用的表 NULL 外的-complemented侧连接(即,a的右侧表 LEFT JOIN 或的左侧表 RIGHT JOIN

  • SQL_BIG_RESULT 或者 SQL_SMALL_RESULT 可以与 优化器 一起使用 GROUP BY DISTINCT 告诉优化器结果集分别有很多行或很小。 因为 SQL_BIG_RESULT ,MySQL在创建时直接使用基于磁盘的临时表,并且更喜欢使用带有 GROUP BY 元素 键的临时表进行排序 因为 SQL_SMALL_RESULT ,MySQL使用内存中的临时表来存储结果表而不是使用排序。 通常不需要这样做。

  • SQL_BUFFER_RESULT 强制将结果放入临时表中。 这有助于MySQL尽早释放表锁,并在需要很长时间将结果集发送到客户端的情况下提供帮助。 此修饰符只能用于顶级 SELECT 语句,不能用于子查询或后续语句 UNION

  • SQL_CALC_FOUND_ROWS 告诉MySQL计算结果集中有多少行,忽略任何 LIMIT 子句。 然后可以使用检索行数 SELECT FOUND_ROWS() 请参见 第12.15节“信息功能”

    注意

    SQL_CALC_FOUND_ROWS 查询修改和相应的 FOUND_ROWS() 功能已被弃用例如MySQL 8.0.17,并会在将来的MySQL版本中删除。 有关 FOUND_ROWS() 替代策略的信息, 请参阅 说明。

  • SQL_CACHE SQL_NO_CACHE 改进剂与之前的MySQL 8.0查询缓存使用。 MySQL 8.0中删除了查询缓存。 SQL_CACHE 修改被移除。 SQL_NO_CACHE 已弃用,无效,将在未来的MySQL版本中删除。

SELECT 来自使用存储引擎(例如 MyISAM 使用表级锁) 的分区表中的 A 仅锁定包含与 SELECT 语句 WHERE 子句 匹配的行的分区 InnoDB 对于使用行级锁定的 存储引擎,不会发生这种情况 。)有关更多信息,请参阅 分区和锁定

13.2.10.1 SELECT ... INTO语法

SELECT ... INTO 形式 SELECT 使查询结果存储在变量或将其写入文件:

  • SELECT ... INTO var_list 选择列值并将它们存储到变量中。

  • SELECT ... INTO OUTFILE 将选定的行写入文件。 可以指定列和行终止符以生成特定的输出格式。

  • SELECT ... INTO DUMPFILE 将单行写入文件而不进行任何格式化。

SELECT 语法描述(见 第13.2.10,“SELECT语法” )显示 INTO 附近的语句结尾条款。 也可以 INTO select_expr 列表后 立即 使用

INTO 条款不应该在嵌套使用 SELECT ,因为这样一个 SELECT 必须将其结果返回到外部环境。

INTO 子句可以命名一个或多个变量的列表,这些变量可以是用户定义的变量,存储过程或函数参数,或存储的程序局部变量。 (在准备好的 SELECT ... INTO OUTFILE 语句中,只允许用户定义的变量;请参见 第13.6.4.2节“局部变量范围和分辨率” 。)

选定的值将分配给变量。 变量的数量必须与列数相匹配。 查询应返回单行。 如果查询未返回任何行,则会发生错误代码为1329的警告( No data ),并且变量值保持不变。 如果查询返回多行,则发生错误1172( Result consisted of more than one row )。 如果语句可能检索多行,则可以使用 LIMIT 1 将结果集限制为单行。

SELECT id,data INTO @x,@ y FROM test.t1 LIMIT 1;

用户变量名称不区分大小写。 请参见 第9.4节“用户定义的变量”

所述 的形式 的选择的行写入到一个文件中。 该文件是在服务器主机上创建的,因此您必须具有 使用此语法 权限。 不能是现有文件,除其他外,它会阻止文件如 数据库表和数据库表被销毁。 系统变量控制文件名的解释。 SELECT ... INTO OUTFILE 'file_name' SELECT FILE file_name /etc/passwd character_set_filesystem

SELECT ... INTO OUTFILE 语句主要用于让您快速将表转储到服务器计算机上的文本文件中。 如果要在服务器主机之外的其他主机上创建生成的文件,通常无法使用, SELECT ... INTO OUTFILE 因为无法相对于服务器主机的文件系统写入文件的路径。

但是,如果MySQL客户端软件安装在远程计算机上,则可以使用客户端命令(例如 在客户端主机上生成文件)。 mysql -e "SELECT ..." > file_name

如果可以使用服务器文件系统上的网络映射路径访问远程主机上文件的位置,则还可以在服务器主机以外的其他主机上创建生成的文件。 在这种情况下, 目标主机上不需要 存在 mysql (或其他一些MySQL客户端程序)。

SELECT ... INTO OUTFILE 是补充 LOAD DATA 列值将写入转换为 CHARACTER SET 子句中 指定的字符集 如果不存在此类子句,则使用 binary 字符集转 储值 实际上,没有字符集转换。 如果结果集包含多个字符集中的列,则输出数据文件也将如此,您可能无法正确重新加载文件。

export_options 语句部分 的语法 FIELDS LINES 语句一起使用 的相同 子句 组成 LOAD DATA 参见 第13.2.7,“LOAD DATA语法” ,以获取有关信息 FIELDS LINES 条款,包括它们的默认值和允许值。

FIELDS ESCAPED BY 控制如何写特殊字符。 如果 FIELDS ESCAPED BY 字符不为空,则在必要时使用它以避免歧义作为输出后面字符之前的前缀:

  • 这个 FIELDS ESCAPED BY 角色

  • 这个 FIELDS [OPTIONALLY] ENCLOSED BY 角色

  • FIELDS TERMINATED BY LINES TERMINATED BY 的第一个字符

  • ASCII NUL (零值字节;转义字符后面实际写入的是ASCII 0 ,而不是零值字节)

FIELDS TERMINATED BY ENCLOSED BY ESCAPED BY ,或 LINES TERMINATED BY 字符 必须 进行转义,这样就可以读取该文件回可靠。 ASCII NUL 被转义,以便使用某些寻呼机更容易查看。

生成的文件不必符合SQL语法,因此不需要转义任何其他内容。

如果 FIELDS ESCAPED BY 字符是空的,没有字符被转义,并且 NULL 是输出 NULL ,没有 \N 指定空的转义字符可能不是一个好主意,特别是如果数据中的字段值包含刚刚给出的列表中的任何字符。

下面是一个以许多程序使用的逗号分隔值(CSV)格式生成文件的示例:

选择a,b,a + b INTO OUTFILE'/tmp/result.txt'
  字段被',''选择性地封闭'''
  由'\ n'终止的线路
  FROM test_table;

如果您使用 INTO DUMPFILE 而不是 INTO OUTFILE ,MySQL只在文件中写入一行,没有任何列或行终止,也没有执行任何转义处理。 如果要将 BLOB 存储 在文件中, 这非常有用

注意

mysqld 帐户 运行 的操作系统用户 创建 INTO OUTFILE INTO DUMPFILE 拥有的 任何文件 (你应该 永远 运行 mysqld的 ,这和其他的原因。)从MySQL 8.0.17中,对文件创建的umask是0640; 您必须具有足够的访问权限才能操作文件内容。 在MySQL 8.0.17之前,umask是0666,并且该文件可由服务器主机上的所有用户写入。 root

如果 secure_file_priv 系统变量设置为非空目录名,则要写入的文件必须位于该目录中。

SELECT ... INTO 作为事件调度程序执行的事件的一部分发生 语句 的上下文中 ,诊断消息(不仅是错误,还包括警告)将写入错误日志,并在Windows上写入应用程序事件日志。 有关其他信息,请参见 第24.4.5节“事件调度程序状态”

13.2.10.2 JOIN语法

MySQL支持 语句 部分 和多表 语句 的以下 JOIN 语法 table_references SELECT DELETE UPDATE

table_references:
    escaped_table_reference[,escaped_table_reference] ......

escaped_table_referencetable_reference
  | {OJ table_reference}

table_referencetable_factor
  |joined_table

table_factortbl_name[PARTITION(partition_names)]
        [[AS] alias] [ index_hint_list]
  | table_subquery[AS] alias[(col_list)]
  | table_references

joined_tabletable_reference{[INNER | CROSS]加入| STRAIGHT_JOIN} table_factor[ join_specification]
  | table_reference{LEFT | RIGHT} [OUTER] JOIN 
  | NATURAL [INNER | {LEFT | RIGHT} [OUTER]]加入table_reference join_specificationtable_referencetable_factor

join_specification
    ON search_condition
  | 使用(join_column_list

join_column_listcolumn_name[,column_name] ......

index_hint_listindex_hint[,index_hint] ......

index_hint
    使用{INDEX | KEY}
      [FOR {JOIN | ORDER BY | GROUP BY}]([ index_list])
  | {IGNORE | FORCE} {INDEX | KEY}
      [FOR {JOIN | ORDER BY | GROUP BY}](index_list

index_listindex_name[,index_name] ......

表引用也称为连接表达式。

表引用(当它引用分区表时)可以包含一个 PARTITION 选项,包括逗号分隔的分区,子分区或两者的列表。 此选项遵循表的名称,并在任何别名声明之前。 此选项的作用是仅从列出的分区或子分区中选择行。 将忽略列表中未命名的任何分区或子分区。 有关更多信息和示例,请参见 第23.5节“分区选择”

table_factor 与标准SQL相比,MySQL中扩展了 语法 标准只接受 table_reference ,而不是在一对括号内的列表。

如果 table_reference 项目 列表中的每个逗号 被视为等同于内部 联接,则这是保守扩展 例如:

SELECT * FROM t1 LEFT JOIN(t2,t3,t4)
                 ON(t2.a = t1.a AND t3.b = t1.b AND t4.c = t1.c)

相当于:

SELECT * FROM t1 LEFT JOIN(t2 CROSS JOIN t3 CROSS JOIN t4)
                 ON(t2.a = t1.a AND t3.b = t1.b AND t4.c = t1.c)

在MySQL, , JOIN CROSS JOIN INNER JOIN 是句法当量(它们可以彼此替换)。 在标准SQL中,它们不等效。 INNER JOIN ON 子句一起 CROSS JOIN 使用,否则使用。

通常,在仅包含内部联接操作的联接表达式中可以忽略括号。 MySQL还支持嵌套连接。 请参见 第8.2.1.7节“嵌套连接优化”

可以指定索引提示以影响MySQL优化器如何使用索引。 有关更多信息,请参见 第8.9.4节“索引提示” 优化器提示和 optimizer_switch 系统变量是影响优化器使用索引的其他方法。 请参见 第8.9.3节“优化程序提示” 第8.9.2节“可切换的优化”

以下列表描述了在编写联接时要考虑的一般因素:

  • 表引用可以使用 使用别名 tbl_name AS alias_name tbl_name alias_name

    SELECT t1.name,t2.salary
      FROM employee AS t1 INNER JOIN info AS t2 ON t1.name = t2.name;
    
    SELECT t1.name,t2.salary
      FROM employee t1 INNER JOIN info t2 ON t1.name = t2.name;
    
  • A table_subquery 也称为 FROM 子句中 的派生表或子查询 请参见 第13.2.11.8节“派生表” 此类子查询 必须 包含别名,以便为子查询结果提供表名,并且可以选择在括号中包含表列名列表。 一个简单的例子如下:

    SELECT * FROM(SELECT 1,2,3)AS t1;
    
  • INNER JOIN , (逗号)在没有连接条件的情况下在语义上是等价的:两者在指定的表之间产生笛卡尔积(即,第一个表中的每一行都连接到第二个表中的每一行)。

    然而,逗号运算符的优先级低于的 INNER JOIN CROSS JOIN LEFT JOIN ,等等。 如果在存在连接条件时将逗号连接与其他连接类型混合,则 可能会出现 表单错误 有关处理此问题的信息将在本节后面给出。 Unknown column 'col_name' in 'on clause'

  • search_condition 使用 ON 是可以在中可以使用的形式的任何条件表达式 WHERE 子句。 通常,该 ON 子句用于指定如何连接表的条件,并且该 WHERE 子句限制要包含在结果集中的行。

  • 如果 a ON USING a中 的右侧表没有匹配的行,则将 LEFT JOIN 所有列设置为的行 NULL 用于右表。 您可以使用此事实在表中查找在另一个表中没有对应项的行:

    SELECT left_tbl。*
      FROM left_tbl LE​​FT JOIN right_tbl ON left_tbl.id = right_tbl.id
      WHERE right_tbl.id IS NULL;
    

    此示例查找 left_tbl 具有 id 不存在 值的 所有行 right_tbl (即, left_tbl 没有相应行的 所有行 right_tbl )。 请参见 第8.2.1.8节“外部连接优化”

  • 子句命名两个表中必须存在的列的列表。 如果表 两者都包含列 ,以下连接将比较两个表中的相应列: USING(join_column_list) a b c1 c2 c3

    a LEFT JOIN b使用(c1,c2,c3)
    
  • NATURAL [LEFT] JOIN 两个表被定义为语义上等同于一个 INNER JOIN 或一个 LEFT JOIN 带有 USING 条款名称存在两个表中的所有列。

  • RIGHT JOIN 类似于 LEFT JOIN 为了使代码可以跨数据库移植,建议您使用 LEFT JOIN 而不是 RIGHT JOIN

  • { OJ ... } 在联接语法描述中显示存在语法只是为了与ODBC兼容。 语法中的花括号应按字面编写; 它们不是语法描述中其他地方使用的metasyntax。

    SELECT left_tbl。*
        FROM {OJ left_tbl LE​​FT OUTER JOIN right_tbl
               ON left_tbl.id = right_tbl.id}
        WHERE right_tbl.id IS NULL;
    

    您可以在其中使用其他类型的连接 { OJ ... } ,例如 INNER JOIN RIGHT OUTER JOIN 这有助于与某些第三方应用程序兼容,但不是官方ODBC语法。

  • STRAIGHT_JOIN 类似于 JOIN ,除了左表总是在右表之前读取。 这可以用于连接优化器以次优顺序处理表的那些(少数)情况。

一些连接示例:

SELECT * FROM table1,table2;

SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.id;

SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id;

SELECT * FROM table1 LEFT JOIN table2 USING(id);

SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id
  LEFT JOIN table3 ON table2.id = table3.id;

自然连接和连接 USING ,包括外连接变体,根据SQL:2003标准进行处理:

  • NATURAL 不显示 联接的冗余列 考虑这组陈述:

    CREATE TABLE t1(i INT,j INT);
    CREATE TABLE t2(k INT,j INT);
    插入t1值(1,1);
    插入t2值(1,1);
    SELECT * FROM t1 NATURAL JOIN t2;
    SELECT * FROM t1 JOIN t2 USING(j);
    

    在第一个 SELECT 语句中,列出 j 现在两个表中,因此成为连接列,因此,根据标准SQL,它应该只在输出中出现一次,而不是两次。 类似地,在第二个SELECT语句中,列 j USING 子句中 命名, 并且应该只在输出中出现一次,而不是两次。

    因此,语句产生了这个输出:

    + ------ + ------ + ------ +
    | j | 我| k |
    + ------ + ------ + ------ +
    | 1 | 1 | 1 |
    + ------ + ------ + ------ +
    + ------ + ------ + ------ +
    | j | 我| k |
    + ------ + ------ + ------ +
    | 1 | 1 | 1 |
    + ------ + ------ + ------ +
    

    根据标准SQL发生冗余列消除和列排序,生成此显示顺序:

    • 首先,两个连接表的合并公共列按它们在第一个表中出现的顺序排列

    • 第二,第一个表所特有的列,按照它们在该表中出现的顺序排列

    • 第三,第二个表所特有的列,它们在该表中出现的顺序

    使用coalesce操作定义替换两个公共列的单个结果列。 也就是说,对于两个 t1.a 而且 t2.a 生成的单个连接列 a 被定义为 a = COALESCE(t1.a, t2.a) ,其中:

    COALESCE(x,y)=(例如,当x不为空时,则为x结束)
    

    如果连接操作是任何其他连接,则连接的结果列由连接表的所有列的串联组成。

    合并列定义的结果是,对于外连接, NULL 如果两列中的一列始终 为合并列,则合并列包含非 的值 NULL 如果两列都不是 NULL ,则两个公共列具有相同的值,因此选择哪一列作为合并列的值无关紧要。 解释这一点的一种简单方法是考虑外连接的合并列由a的内部表的公共列表示 JOIN 假设表 t1(a, b) ,并 t2(a, c) 具有下列内容:

    t1 t2
    ---- ----
    1 x 2 z
    2 y 3 w
    

    然后,对于此连接,列 a 包含以下值 t1.a

    MySQL的> SELECT * FROM t1 NATURAL LEFT JOIN t2;
    + ------ + ------ + ------ +
    | a | b | c |
    + ------ + ------ + ------ +
    | 1 | x | NULL |
    | 2 | y | z |
    + ------ + ------ + ------ +
    

    相反,对于此连接,列 a 包含值 t2.a

    MySQL的> SELECT * FROM t1 NATURAL RIGHT JOIN t2;
    + ------ + ------ + ------ +
    | a | c | b |
    + ------ + ------ + ------ +
    | 2 | z | y |
    | 3 | w | NULL |
    + ------ + ------ + ------ +
    

    将这些结果与其他等效查询进行比较 JOIN ... ON

    MySQL的> SELECT * FROM t1 LEFT JOIN t2 ON (t1.a = t2.a);
    + ------ + ------ + ------ + ------ +
    | a | b | a | c |
    + ------ + ------ + ------ + ------ +
    | 1 | x | NULL | NULL |
    | 2 | y | 2 | z |
    + ------ + ------ + ------ + ------ +
    
    MySQL的> SELECT * FROM t1 RIGHT JOIN t2 ON (t1.a = t2.a);
    + ------ + ------ + ------ + ------ +
    | a | b | a | c |
    + ------ + ------ + ------ + ------ +
    | 2 | y | 2 | z |
    | NULL | NULL | 3 | w |
    + ------ + ------ + ------ + ------ +
    
  • USING 子句可以改写为一个 ON 用于比较对应列子句。 然而,虽然 USING 并且 ON 相似,但它们并不完全相同。 考虑以下两个查询:

    a LEFT JOIN b使用(c1,c2,c3)
    a LEFT JOIN b ON a.c1 = b.c1 AND a.c2 = b.c2 AND a.c3 = b.c3
    

    关于确定哪些行满足连接条件,两个连接在语义上是相同的。

    关于确定要显示哪些列以进行 SELECT * 扩展,这两个连接在语义上不相同。 USING 而加入选择对应列的聚结的值, ON 从所有表加入选择的所有列。 对于 USING 连接,请 SELECT * 选择以下值:

    COALESCE(a.c1,b.c1),COALESCE(a.c2,b.c2),COALESCE(a.c3,b.c3)
    

    为了 ON 连接,请 SELECT * 选择以下值:

    a.c1,a.c2,a.c3,b.c1,b.c2,b.c3
    

    使用内部联接, COALESCE(a.c1, b.c1) 两者中 的相同 a.c1 b.c1 两个列具有相同的值。 使用外连接(例如 LEFT JOIN ),两列中的一列可以 NULL 结果中省略了该列。

  • 一个 ON 子句只能参考它的操作数。

    例:

    CREATE TABLE t1(i1 INT);
    CREATE TABLE t2(i2 INT);
    CREATE TABLE t3(i3 INT);
    SELECT * FROM t1 JOIN t2 ON(i1 = i3)JOIN t3;
    

    该语句因 Unknown column 'i3' in 'on clause' 错误而 失败, 因为它 i3 是一个列 t3 ,它不是该 ON 子句 的操作数 要启用联接,请按如下所示重写语句:

    SELECT * FROM t1 JOIN t2 JOIN t3 ON(i1 = i3);
    
  • JOIN 优先级高于逗号运算符( , ),因此连接表达式 t1, t2 JOIN t3 被解释为 (t1, (t2 JOIN t3)) ,而不是 ((t1, t2) JOIN t3) 这会影响使用 ON 子句的 语句, 因为该子句只能引用连接操作数中的列,并且优先级会影响对这些操作数的解释。

    例:

    CREATE TABLE t1(i1 INT,j1 INT);
    CREATE TABLE t2(i2 INT,j2 INT);
    CREATE TABLE t3(i3 INT,j3 INT);
    插入t1值(1,1);
    插入t2值(1,1);
    插入t3值(1,1);
    SELECT * FROM t1,t2 JOIN t3 ON(t1.i1 = t3.i3);
    

    JOIN 过逗号运算符的优先级,所以对于操作数 ON 子句 t2 t3 因为 t1.i1 不是任何一个操作数中的列,结果是 Unknown column 't1.i1' in 'on clause' 错误。

    要启用联接,请使用以下任一策略:

    • 使用括号显式地对前两个表进行分组,以使 ON 子句 的操作数为 (t1, t2) t3

      SELECT * FROM(t1,t2)JOIN t3 ON(t1.i1 = t3.i3);
      
    • 避免使用逗号运算符 JOIN 而是 使用

      SELECT * FROM t1 JOIN t2 JOIN t3 ON(t1.i1 = t3.i3);
      

    优先级相同的解释也适用于与混合逗号操作语句 INNER JOIN CROSS JOIN LEFT JOIN ,并且 RIGHT JOIN ,所有这些都具有比逗号操作符更高的优先级。

  • 与SQL:2003标准相比,MySQL扩展是MySQL允许您限定常见(合并)列 NATURAL USING 连接,而标准不允许。

13.2.10.3 UNION语法

选择 ...
UNION [全部| DISTINCT]选择......
[UNION [全部| DISTINCT] SELECT ...]

UNION 用于将多个 SELECT 语句 的结果组合 到单个结果集中。

第一个 SELECT 语句中的列名称用作返回结果的列名称。 在每个 SELECT 语句的 相应位置列出的选定列 应具有相同的数据类型。 (例如,第一个语句选择的第一列应该与其他语句选择的第一列具有相同的类型。)

如果相应 SELECT 的数据类型 不匹配,则 UNION 结果中 列的类型和长度 会考虑所有 SELECT 语句 检索的值 例如,请考虑以下事项:

MySQL的> SELECT REPEAT('a',1) UNION SELECT REPEAT('b',10);
+ --------------- +
| 重复('a',1)|
+ --------------- +
| a |
| bbbbbbbbbb |
+ --------------- +

这些 SELECT 语句是普通的select语句,但有以下限制:

  • 只有最后一个 SELECT 语句可以使用 INTO OUTFILE (但是,整个 UNION 结果将写入文件。)

  • HIGH_PRIORITY 不能与 SELECT 作为a的一部分的语句 一起使用 UNION 如果为第一个指定它 SELECT ,则无效。 如果为任何后续 SELECT 语句 指定它,则会 产生语法错误。

默认行为 UNION 是从结果中删除重复的行。 可选 DISTINCT 关键字除了默认值之外没有任何效果,因为它还指定了重复行删除。 使用可选 ALL 关键字,不会发生重复行删除,结果包括所有 SELECT 语句中的 所有匹配行

你可以混合 UNION ALL UNION DISTINCT 在相同的查询。 UNION 处理 混合 类型,使得 DISTINCT 联合覆盖 ALL 其左侧的 任何 联合。 DISTINCT 工会可以明确,通过使用来产生 UNION DISTINCT 或隐式地通过使用 UNION 没有以下 DISTINCT ALL 关键字。

要应用 ORDER BY LIMIT 个人 SELECT ,请将子句放在括起来的括号内 SELECT

(选择一个FROM t1 WHERE a = 10 AND B = 1 ORDER by LIMIT 10)
联盟
(选择一个FROM t2 WHERE a = 11 AND B = 2 ORDER by LIMIT 10);

但是, ORDER BY 对于单个 SELECT 语句的 使用 并不意味着行在最终结果中出现的顺序,因为 UNION 默认情况下会生成一组无序行。 因此, ORDER BY 在此上下文中 的使用 通常与结合使用 LIMIT ,以便它用于确定要检索的所选行的子集 SELECT ,即使它不一定影响最终 UNION 结果 中那些行的顺序 如果 ORDER BY 没有出现 LIMIT SELECT ,它被优化掉,因为它不会有任何效果呢。

要使用 ORDER BY or LIMIT 子句对整个 UNION 结果 进行排序或限制 ,请将各个 SELECT 语句 括起来 并放在 最后一个 ORDER BY LIMIT 之后。 以下示例使用两个子句:

(选择一个FROM t1 WHERE a = 10 AND B = 1)
联盟
(选择一个FROM t2 WHERE a = 11 AND B = 2)
订购限额10;

没有括号的语句相当于刚刚显示的一个括号。

这种类型 ORDER BY 不能使用包含表名的列引用(即 tbl_name col_name 格式的 名称 )。 相反,在第一个 SELECT 语句中 提供列别名 并引用其中的别名 ORDER BY (或者,请参阅 ORDER BY 使用其列位置 中的 列。但是,不推荐使用列位置。)

此外,如果要排序的列是别名,则该 ORDER BY 子句 必须 引用别名,而不是列名。 以下第一个语句将起作用,但第二个语句将失败并显示 Unknown column 'a' in 'order clause' 错误:

(选择一个AS b FROM t)UNION(SELECT ...)ORDER BY b;
(选择一个AS b FROM t)UNION(SELECT ...)ORDER BY a;

要使 UNION 结果中的行包含由每个行检索到的行集,请在每个行中 SELECT 选择一个附加列 SELECT 以用作排序列,并 ORDER BY 在最后 添加 以下内容 SELECT

(SELECT 1 AS sort_col,col1a,col1b,... FROM t1)
联盟
(SELECT 2,col2a,col2b,... FROM t2)ORDER BY sort_col;

要在单个 SELECT 结果中 另外维护排序顺序 ,请在 ORDER BY 子句中 添加辅助列

(SELECT 1 AS sort_col,col1a,col1b,... FROM t1)
联盟
(SELECT 2,col2a,col2b,... FROM t2)ORDER BY sort_col,col1a;

使用附加列还可以确定 SELECT 每行来自 哪一 行。 额外列也可以提供其他标识信息,例如表示表名的字符串。

UNION 具有 ORDER BY 子句中 的聚合函数的查询将 被拒绝并出现 ER_AGGREGATE_ORDER_FOR_UNION 错误。 例:

SELECT 1 AS foo UNION SELECT 2 ORDER BY MAX(1);

13.2.11子查询语法

子查询是 SELECT 另一个语句中的语句。

支持SQL标准所需的所有子查询表单和操作,以及一些特定于MySQL的功能。

以下是子查询的示例:

SELECT * FROM t1 WHERE column1 =(SELECT column1 FROM t2);

在此示例中, SELECT * FROM t1 ... 外部查询 (或 外部语句 ),并且 (SELECT column1 FROM t2) 子查询 我们说子查询 嵌套 在外部查询中,实际上可以将子查询嵌套在其他子查询中,达到相当深的程度。 子查询必须始终出现在括号内。

子查询的主要优点是:

  • 它们允许 结构化的 查询, 以便可以隔离语句的每个部分。

  • 它们提供了执行操作的替代方法,否则需要复杂的连接和联合。

  • 许多人发现子查询比复杂的联接或联合更具可读性。 实际上,正是子查询的创新给人们提供了调用早期SQL 结构化查询语言 的最初想法

下面是一个示例语句,显示了SQL标准指定并在MySQL中支持的子查询语法的主要观点:

从t1删除
在哪里>任何人
 (SELECT COUNT(*)/ * no提示* / FROM t2
  什么不存在
   (SELECT * FROM t3
    在哪里(5 * t2.s1,77)=
     (从T4 UNION SELECT 50,77 FROM中选择50,11 * s1
      (SELECT * FROM t5)AS t5)));

子查询可以返回标量(单个值),单个行,单个列或表(一个或多个列的一行或多行)。 这些称为标量,列,行和表子查询。 返回特定类型结果的子查询通常只能在某些上下文中使用,如以下各节所述。

对可以使用子查询的语句类型的限制很少。 子查询可以包含许多普通的关键字或条款 SELECT 可能包含: DISTINCT GROUP BY ORDER BY LIMIT ,连接,索引提示, UNION 结构,注释,函数等等。

子查询的外部语句可以是任何一个: SELECT INSERT UPDATE DELETE SET ,或 DO

在MySQL中,您无法修改表并从子查询中的同一个表中进行选择。 这适用于语句,例如 DELETE INSERT REPLACE UPDATE ,和(因为子查询可以在中使用 SET 子句) LOAD DATA

有关优化程序如何处理子查询的信息,请参见 第8.2.2节“优化子查询,派生表,视图引用和公用表表达式” 有关子查询使用限制的讨论,包括某些形式的子查询语法的性能问题,请参见 第C.4节“子查询的限制”

13.2.11.1子查询作为标量操作数

在其最简单的形式中,子查询是一个返回单个值的标量子查询。 标量子查询是一个简单的操作数,您几乎可以在单个列值或文字合法的任何地方使用它,并且您可以期望它具有所有操作数具有的特征:数据类型,长度,它可以指示它是 NULL ,依此类推。 例如:

CREATE TABLE t1(s1 INT,s2 CHAR(5)NOT NULL);
插入t1 VALUES(100,'abcde');
SELECT(SELECT s2 FROM t1);

其中的子查询 SELECT 返回单个值( 'abcde' ),该 具有数据类型 CHAR ,长度为5,字符集和排序规则等于当时有效的默认值 CREATE TABLE ,并指示列中的值可以是 NULL 不会复制标量子查询所选值的可为空性,因为如果子查询结果为空,则结果为 NULL 对于刚刚显示的子查询,如果 t1 为空,则结果 NULL 即使 s2 NOT NULL

有一些上下文不能使用标量子查询。 如果语句仅允许文字值,则不能使用子查询。 例如, LIMIT 需要文字整数参数,并且 LOAD DATA 需要文字字符串文件名。 您不能使用子查询来提供这些值。

当您在以下部分中看到包含相当简洁的构造的示例时,请 (SELECT column1 FROM t1) 想象您自己的代码包含更多样化和复杂的构造。

假设我们制作两个表:

CREATE TABLE t1(s1 INT);
插入t1值(1);
CREATE TABLE t2(s1 INT);
插入t2值(2);

然后执行 SELECT

SELECT(SELECT s1 FROM t2)FROM t1;

结果是 2 因为 t2 包含 s1 一个值为的 的行 2

标量子查询可以是表达式的一部分,但请记住括号,即使子查询是为函数提供参数的操作数。 例如:

SELECT UPPER((从s1中选择s1))FROM t2;

13.2.11.2使用子查询进行比较

子查询的最常见用法是以下形式:

non_subquery_operand comparison_operatorsubquery

comparison_operator 这些运营商之一 在哪里

=> <> = <= <>!= <=>

例如:

... WHERE'a'=(SELECT column1 FROM t1)

MySQL也允许这种结构:

non_subquery_operand喜欢(subquery

有一次,子查询的唯一合法位置是在比较的右侧,您可能仍然会发现一些坚持这一点的旧DBMS。

下面是一个常见形式子查询比较的示例,您无法对连接执行此操作。 它查找表中的所有行, t1 column1 值等于表中的最大值 t2

SELECT * FROM t1
  WHERE column1 =(SELECT MAX(column2)FROM t2);

这是另一个例子,连接也是不可能的,因为它涉及聚合其中一个表。 它查找表中 t1 包含在给定列中出现两次的值的 所有行

SELECT * FROM t1 AS t
  WHERE 2 =(SELECT COUNT(*)FROM t1 WHERE t1.id = t.id);

为了将子查询与标量进行比较,子查询必须返回标量。 为了将子查询与行构造函数进行比较,子查询必须是行子查询,该子查询返回与行构造函数具有相同数量值的行。 请参见 第13.2.11.5节“行子查询”

13.2.11.3具有ANY,IN或SOME的子查询

句法:

operand comparison_operatorANY(subqueryoperandIN(subquerySOME(operand comparison_operatorsubquery

comparison_operator 这些运营商之一 在哪里

=> <> = <= <>!=

ANY 关键字,它必须遵循一个比较操作符,表示 回报 TRUE 如果比较 TRUE ANY 列的子查询返回的值。 例如:

SELECT s1 FROM t1 WHERE s1> ANY(SELECT s1 FROM t2);

假设表 t1 有一行 包含 (10) 表达是 TRUE 如果表 t2 包含 (21,14,7) 因为有一个值 7 t2 小于 10 表达式是 FALSE if表 t2 包含 (20,10) ,或者表 t2 是否为空。 如果表 包含 表达式是 未知的 (即 NULL t2(NULL,NULL,NULL)

与子查询一起使用时,该单词 IN 是别名 = ANY 因此,这两个陈述是相同的:

SELECT s1 FROM t1 WHERE s1 = ANY(SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 IN(SELECT s1 FROM t2);

IN 并且 = ANY 与表达式列表一起使用时不是同义词。 IN 可以采用表达式列表,但 = ANY 不能。 请参见 第12.3.2节“比较函数和运算符”

NOT IN 不是别名 <> ANY ,而是for <> ALL 请参见 第13.2.11.4节“带有ALL的子查询”

这个词 SOME 是别名 ANY 因此,这两个陈述是相同的:

SELECT s1 FROM t1 WHERE s1 <> ANY(SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 <> SOME(SELECT s1 FROM t2);

使用这个词 SOME 很少见,但这个例子说明了它可能有用的原因。 对于大多数人来说,英语短语 a不等于任何b 意味着 没有b等于a ”, 但这不是SQL语法的含义。 语法意味着 有一些不相等的b。 使用 <> SOME 相反有助于确保每个人都理解查询的真正含义。

13.2.11.4包含ALL的子查询

句法:

operand comparison_operator全部(subquery

ALL 必须遵循比较运算符 的单词 表示 如果进行比较则 返回 TRUE TRUE ALL 列的子查询返回的值。 例如:

SELECT s1 FROM t1 WHERE s1> ALL(SELECT s1 FROM t2);

假设表 t1 有一行 包含 (10) 表达式是 TRUE if表 t2 包含 (-5,0,+5) 因为 10 大于所有三个值 t2 表达是 FALSE 如果表 t2 包含 (12,6,NULL,-100) ,因为有一个单一的值 12 在表 t2 是大于 10 如果表 包含 表达式是 未知的 (即 NULL t2 (0,NULL,1)

最后,表达式是 TRUE 表格 t2 是否为空。 因此,以下表达式是 TRUE t2 为空时:

SELECT * FROM t1 WHERE 1> ALL(SELECT s1 FROM t2);

但是这个表达式是 NULL t2 空时:

SELECT * FROM t1 WHERE 1>(SELECT s1 FROM t2);

另外,以下表达式是 NULL t2 为空时:

SELECT * FROM t1 WHERE 1> ALL(SELECT MAX(s1)FROM t2);

通常, 包含 NULL 空表的表 边缘情况”。 在编写子查询时,请始终考虑是否考虑了这两种可能性。

NOT IN 是别名 <> ALL 因此,这两个陈述是相同的:

SELECT s1 FROM t1 WHERE s1 <> ALL(SELECT s1 FROM t2);
SELECT s1 FROM t1 WHERE s1 NOT IN(SELECT s1 FROM t2);

13.2.11.5行子查询

标量或列子查询返回单个值或一列值。 行子查询 是一个子查询变体返回单个行,因此可以返回多个列值。 行子查询比较的合法运算符是:

=> <> = <= <>!= <=>

这是两个例子:

SELECT * FROM t1
  WHERE(col1,col2)=(SELECT col3,col4 FROM t2 WHERE id = 10);
SELECT * FROM t1
  WHERE ROW(col1,col2)=(SELECT col3,col4 FROM t2 WHERE id = 10);

对于这两个查询,如果表 t2 包含单行 id = 10 ,则子查询返回单行。 如果此行的 col3 col4 值等于 任何行的值 col1 col2 t1 ,则 WHERE 表达式为, TRUE 并且每个查询都返回这些 t1 行。 如果 t2 col3 col4 值不等于 任何 行的 col1 col2 t1 ,则表达式为 FALSE ,并且查询返回空结果集。 表达方式 未知 (即, NULL )如果子查询没有产生任何行。 如果子查询产生多行,则会发生错误,因为行子查询最多只能返回一行。

有关每个运算符如何进行行比较的信息,请参见 第12.3.2节“比较函数和运算符”

表达 (1,2) ROW(1,2) 有时被称为 行构造函数 两者是等价的。 行构造函数和子查询返回的行必须包含相同数量的值。

行构造函数用于与返回两列或更多列的子查询进行比较。 当子查询返回单个列时,这被视为标量值而不是行,因此行构造函数不能与不返回至少两列的子查询一起使用。 因此,以下查询失败并出现语法错误:

SELECT * FROM t1 WHERE ROW(1)=(SELECT column1 FROM t2)

行构造函数在其他上下文中是合法的。 例如,以下两个语句在语义上是等效的(并且由优化器以相同的方式处理):

SELECT * FROM t1 WHERE(column1,column2)=(1,1);
SELECT * FROM t1 WHERE column1 = 1 AND column2 = 1;

以下查询回答请求, 查找表 t1 中也存在于表中的 所有行 t2

SELECT column1,column2,column3
  从t1
  WHERE(column1,column2,column3)IN
         (SELECT column1,column2,column3 FROM t2);

有关优化程序和行构造函数的更多信息,请参见 第8.2.1.21节“行构造函数表达式优化”

13.2.11.6具有EXISTS或NOT EXISTS的子查询

如果一个子查询返回任何行可言, 例如: EXISTS subquery TRUE NOT EXISTS subquery FALSE

SELECT column1 FROM t1 WHERE EXISTS(SELECT * FROM t2);

传统上, EXISTS 子查询开始于 SELECT * ,但它可以以 SELECT 5 SELECT column1 或任何东西 开头 MySQL忽略了 SELECT 这样一个子查询中 列表,所以没有区别。

对于前面的示例,如果 t2 包含任何行,甚至包含除了 NULL 值之外的 ,则 EXISTS 条件为 TRUE 这实际上是一个不太可能的例子,因为 [NOT] EXISTS 子查询几乎总是包含相关性。 以下是一些更现实的例子:

  • 一个或多个城市有哪种商店?

    SELECT DISTINCT store_type FROM stores
      在哪里存在(SELECT * FROM cities_stores
                    WHERE cities_stores.store_type = stores.store_type);
    
  • 没有城市有什么样的商店?

    SELECT DISTINCT store_type FROM stores
      什么不存在(SELECT * FROM cities_stores
                        WHERE cities_stores.store_type = stores.store_type);
    
  • 所有城市都有哪种商店?

    SELECT DISTINCT store_type FROM存储s1
      什么地方没有(
        SELECT * FROM CITY不存在(
          SELECT * FROM cities_stores
           cities_ cities.city = cities.city
           AND cities_stores.store_type = stores.store_type));
    

最后一个示例是双嵌套 NOT EXISTS 查询。 也就是说,它在一个 NOT EXISTS 子句中有一个 NOT EXISTS 子句。 在形式上,它回答了 一个城市存在与不存在的商店 Stores ”的问题 吗? 但它更容易地说,嵌套 NOT EXISTS 的答案的问题 对所有 x TRUE y

13.2.11.7相关子查询

相关子 是包含要也出现在外部查询表的基准的子查询。 例如:

SELECT * FROM t1
  WHERE column1 = ANY(SELECT column1 FROM t2
                       WHERE t2.column2 = t1.column2);

请注意,子查询包含对列的引用 t1 ,即使子查询的 FROM 子句未提及表 t1 因此,MySQL在子查询之外查找,并 t1 在外部查询中查找。

假设该表 t1 包含一行where column1 = 5 column2 = 6 ; 同时,表中 t2 包含一行 column1 = 5 column2 = 7 简单的表达式 ... WHERE column1 = ANY (SELECT column1 FROM t2) TRUE ,但在这个例子中, WHERE 子查询中 子句是 FALSE (因为 (5,6) 不等于 (5,7) ),所以表达式作为一个整体 FALSE

范围规则: MySQL从内到外进行评估。 例如:

SELECT column1 FROM t1 AS x
  WHERE x.column1 =(SELECT column1 FROM t2 AS x
    WHERE x.column1 =(SELECT column1 FROM t3
      WHERE x.column2 = t3.column1));

在此语句中, x.column2 必须是表中的列, t2 因为 SELECT column1 FROM t2 AS x ... 重命名 t2 它不是表中的列, t1 因为它 SELECT column1 FROM t1 ... 是一个 更远 的外部查询

对于 HAVING or或 ORDER BY 子句中的 子查询 ,MySQL还会在外部选择列表中查找列名。

对于某些情况,优化了相关子查询。 例如:

valIN(key_valtbl_name哪里选择correlated_condition

否则,它们效率低下并且可能很慢。 将查询重写为连接可能会提高性能。

相关子查询中的聚合函数可能包含外部引用,前提是该函数只包含外部引用,并且该函数不包含在另一个函数或表达式中。

13.2.11.8派生表

本节讨论派生表的一般特征。 有关以 LATERAL 关键字 开头的横向派生表的 信息 ,请参见 第13.2.11.9节“横向派生表”

派生表是一个表达式,用于在查询 FROM 子句 的范围内生成表 例如, SELECT statement FROM 子句中 的子查询 是派生表:

SELECT ... FROM(subquery)[AS] tbl_name...

JSON_TABLE() 函数生成一个表,并提供另一种创建派生表的方法:

SELECT * FROM JSON_TABLE(arg_list)[AS] tbl_name...

子句是必需的,因为子句中的每个表都 必须具有名称。 派生表中的任何列都必须具有唯一名称。 或者, 可以跟随派生表列的带括号的名称列表: [AS] tbl_name FROM tbl_name

SELECT ... FROM(subquery)[AS] tbl_namecol_list)...

列名称的数量必须与表列的数量相同。

为了便于说明,假设您有此表:

CREATE TABLE t1(s1 INT,s2 CHAR(5),s3 FLOAT);

以下是 FROM 使用示例表 子句中使用 子查询的 方法:

插入t1值(1,'1',1.0);
插入t1值(2,'2',2.0);
SELECT sb1,sb2,sb3
  FROM(SELECT s1 AS sb1,s2 AS sb2,s3 * 2 AS sb3 FROM t1)AS sb
  WHERE sb1> 1;

结果:

+ ------ + ------ + ------ +
| sb1 | sb2 | sb3 |
+ ------ + ------ + ------ +
| 2 | 2 | 4 |
+ ------ + ------ + ------ +

这是另一个例子:假设您想知道分组表的一组总和的平均值。 这不起作用:

SELECT AVG(SUM(column1))FROM t1 GROUP BY column1;

但是,此查询提供了所需的信息:

SELECT AVG(sum_column1)
  FROM(SELECT SUM(column1)AS sum_column1
        FROM t1 GROUP BY column1)AS t1;

请注意,子查询( sum_column1 )中 使用的列名称 在外部查询中被识别。

派生表的列名来自其选择列表:

MySQL的> SELECT * FROM (SELECT 1, 2, 3, 4) AS dt;
+ --- + --- + --- + --- +
| 1 | 2 | 3 | 4 |
+ --- + --- + --- + --- +
| 1 | 2 | 3 | 4 |
+ --- + --- + --- + --- +

要显式提供列名,请使用带括号的列名列表跟随派生表名:

MySQL的> SELECT * FROM (SELECT 1, 2, 3, 4) AS dt (a, b, c, d);
+ --- + --- + --- + --- +
| a | b | c | d |
+ --- + --- + --- + --- +
| 1 | 2 | 3 | 4 |
+ --- + --- + --- + --- +

派生表可以返回标量,列,行或表。

派生表受这些限制的约束:

  • 派生表不能是相关子查询。

  • 派生表不能包含对其他表的引用 SELECT

  • 在MySQL 8.0.14之前,派生表不能包含外部引用。 这是在MySQL 8.0.14中解除的MySQL限制,而不是SQL标准的限制。 例如, dt 以下查询中 的派生表 包含 对外部查询中 t1.b 的表 的引用 t1

    SELECT * FROM t1
    在哪里t1.d>(SELECT AVG(dt.a)
                    FROM(SELECT SUM(t2.a)AS a
                          从t2开始
                          在哪里t2.b = t1.b GROUP BY t2.c)dt
                  在哪里dt.a> 10);
    

    该查询在MySQL 8.0.14及更高版本中有效。 在8.0.14之前,它会产生错误: Unknown column 't1.b' in 'where clause'

优化器以 EXPLAIN 不需要实现 派生表的方式确定有关派生表的信息 请参见 第8.2.2.4节“使用合并或实现优化派生表,视图引用和公用表表达式”

在某些情况下,使用 EXPLAIN SELECT 将修改表数据 是可能的 如果外部查询访问任何表并且内部查询调用更改表的一行或多行的存储函数,则会发生这种情况。 假设有两个表 t1 ,并 t2 在数据库 d1 和存储功能 f1 来修改 t2 ,如下所示创建:

创建数据库d1;
使用d1;
CREATE TABLE t1(c1 INT);
CREATE TABLE t2(c1 INT);
CREATE FUNCTION f1(p1 INT)RETURNS INT
  开始
    插入t2值(p1);
    返回p1;
  结束;

直接在an中引用该函数 EXPLAIN SELECT 对此没有影响 t2 ,如下所示:

MySQL的> SELECT * FROM t2;
空集(0.02秒)

MySQL的> EXPLAIN SELECT f1(5)\G
*************************** 1。排******************** *******
           id:1
  select_type:SIMPLE
        table:NULL
   分区:NULL
         type:NULL
possible_keys:NULL
          key:NULL
      key_len:NULL
          ref:NULL
         rows:NULL
     已过滤:NULL
        额外:不使用表格
1排(0.01秒)

MySQL的> SELECT * FROM t2;
空集(0.01秒)

这是因为 SELECT 语句没有引用任何表,如 输出 table Extra 列中所示。 以下嵌套也是如此 SELECT

MySQL的> EXPLAIN SELECT NOW() AS a1, (SELECT f1(5)) AS a2\G
*************************** 1。排******************** *******
           id:1
  select_type:PRIMARY
        table:NULL
         type:NULL
possible_keys:NULL
          key:NULL
      key_len:NULL
          ref:NULL
         rows:NULL
     已过滤:NULL
        额外:不使用表格
1排,1警告(0.00秒)

MySQL的> SHOW WARNINGS;
+ ------- + ------ + ---------------------------------- -------- +
| 等级| 代码| 消息|
+ ------- + ------ + ---------------------------------- -------- +
| 注意| 1249 | 在优化期间,选择2减少了|
+ ------- + ------ + ---------------------------------- -------- +
1排(0.00秒)

MySQL的> SELECT * FROM t2;
空集(0.00秒)

但是,如果外部 SELECT 引用任何表,优化器也会在子查询中执行语句, t2 并修改 结果

MySQL的> EXPLAIN SELECT * FROM t1 AS a1, (SELECT f1(5)) AS a2\G
*************************** 1。排******************** *******
           id:1
  select_type:PRIMARY
        table:<derived2>
   分区:NULL
         类型:系统
possible_keys:NULL
          key:NULL
      key_len:NULL
          ref:NULL
         行:1
     过滤:100.00
        额外:NULL
*************************** 2.排******************** *******
           id:1
  select_type:PRIMARY
        表:a1
   分区:NULL
         类型:全部
possible_keys:NULL
          key:NULL
      key_len:NULL
          ref:NULL
         行:1
     过滤:100.00
        额外:NULL
*************************** 3。排******************** *******
           id:2
  select_type:DERIVED
        table:NULL
   分区:NULL
         type:NULL
possible_keys:NULL
          key:NULL
      key_len:NULL
          ref:NULL
         rows:NULL
     已过滤:NULL
        额外:不使用表格
3组(0.00秒)

MySQL的> SELECT * FROM t2;
+ ------ +
| c1 |
+ ------ +
| 5 |
+ ------ +
1排(0.00秒)

这也意味着 EXPLAIN SELECT 诸如此处所示 语句可能需要很长时间才能执行,因为该 BENCHMARK() 函数对于每一行执行一次 t1

EXPLINE SELECT * FROM t1 AS a1,(SELECT BENCHMARK(1000000,MD5(NOW())));

13.2.11.9横向派生表

派生表通常不能引用同一 FROM 子句 中前面表的(依赖于)列 从MySQL 8.0.14开始,可以将派生表定义为横向派生表,以指定允许此类引用。

使用 第13.2.11.8节“派生表”中 讨论的语法指定非 边界派生表 横向派生表的语法与非边界派生表的语法相同,只是 LATERAL 在派生表规范之前指定 了关键字 LATERAL 关键字必须先于每个表以用作横向派生表。

横向派生表受这些限制:

  • 横向派生表可以只发生在一个 FROM 条款,无论是在用逗号分隔的表的列表中或在加入规范( JOIN INNER JOIN CROSS JOIN LEFT [OUTER] JOIN ,或 RIGHT [OUTER] JOIN )。

  • 如果横向派生表是在一个连接子句的右操作数和包含对左操作数的引用,所述加入操作必须是 INNER JOIN CROSS JOIN ,或 LEFT [OUTER] JOIN

    如果表是在左边的操作数,并包含右操作数的引用,连接操作必须是 INNER JOIN CROSS JOIN RIGHT [OUTER] JOIN

  • 如果横向派生表引用聚合函数,则函数的聚合查询不能是拥有 FROM 横向派生表发生 子句 的聚合查询

  • 根据SQL标准,表函数具有隐式 LATERAL ,因此它的行为与8.0.14之前的MySQL 8.0版本相同。 但是,按照标准, LATERAL 之前不允许 使用 该词 JSON_TABLE() ,即使它是隐含的。

以下讨论显示了横向派生表如何使某些SQL操作成为可能,这些SQL操作无法使用非边界派生表或需要效率较低的变通方法。

假设我们想要解决这个问题:给出销售人员中的人员表(每行描述销售人员的成员),以及所有销售的表格(每行描述销售:销售人员,客户,金额) ,日期),确定每个销售人员最大销售的规模和客户。 这个问题可以通过两种方式解决。

解决问题的第一种方法:对于每个销售人员,计算最大销售量,并找到提供此最大值的客户。 在MySQL中,可以这样做:

选择
  salesperson.name,
  - 找到该销售人员的最大销售规模
  (SELECT MAX(金额)AS金额
    来自all_sales
    所有all_sales.salesperson_id = salesperson.id)
  AS金额,
  - 找到最大尺寸的客户
  (SELECT customer_name
    来自all_sales
    所有all_sales.salesperson_id = salesperson.id
    AND all_sales.amount =
         - 再次找到最大尺寸
         (SELECT MAX(金额)AS金额
           来自all_sales
           all where allsales.salesperson_id = salesperson.id))
  AS customer_name
  营业员;

该查询效率低下,因为它计算每个销售人员两次的最大大小(一次在第一个子查询中,一次在第二个子查询中)。

我们可以尝试通过计算每个销售人员一次的最大值并 在派生表中 缓存 来实现效率提升 ,如此修改后的查询所示:

选择
  salesperson.name,
  max_sale.amount,
  max_sale_customer.customer_name
  营业员,
  - 计算最大大小,将其缓存在瞬态派生表max_sale中
  (SELECT MAX(金额)AS金额
    来自all_sales
    所有all_sales.salesperson_id = salesperson.id)
  AS max_sale,
  - 找到客户,重用缓存的最大大小
  (SELECT customer_name
    来自all_sales
    所有all_sales.salesperson_id = salesperson.id
    AND all_sales.amount =
        - 缓存的最大大小
        max_sale.amount)
  AS max_sale_customer;

但是,该查询在SQL-92中是非法的,因为派生表不能依赖于同一 FROM 子句 中的其他表 派生表在查询的持续时间内必须是常量,不包含对其他列的引用 FROM 表的 如上所述,查询会产生此错误:

ERROR 1054(42S22):'where子句'中的未知列'salesperson.id'

在SQL:1999中,如果派生表前面有 LATERAL 关键字(这意味着 此派生表依赖于其左侧的先前表 ,则查询变得合法

选择
  salesperson.name,
  max_sale.amount,
  max_sale_customer.customer_name
  营业员,
  - 计算最大大小,将其缓存在瞬态派生表max_sale中
  (SELECT MAX(金额)AS金额
    来自all_sales
    所有all_sales.salesperson_id = salesperson.id)
  AS max_sale,
  - 找到客户,重用缓存的最大大小
  (SELECT customer_name
    来自all_sales
    所有all_sales.salesperson_id = salesperson.id
    AND all_sales.amount =
        - 缓存的最大大小
        max_sale.amount)
  AS max_sale_customer;

横向派生表不需要是常量的,并且每次从顶部查询处理它所依赖的前一个表的新行时都会更新。

解决问题的第二种方法:如果 SELECT 列表中 的子查询 可以返回多个列 ,则可以使用不同的解决方案

选择
  salesperson.name,
  - 同时找到最大尺寸和客户
  (选择金额,customer_name
    来自all_sales
    所有all_sales.salesperson_id = salesperson.id
    按订单金额DESC限制1)
  营业员;

这是有效但非法的。 它不起作用,因为此类子查询只能返回一列:

ERROR 1241(21000):操作数应包含1列

重写查询的一种尝试是从派生表中选择多个列:

选择
  salesperson.name,
  max_sale.amount,
  max_sale.customer_name
  营业员,
  - 同时找到最大尺寸和客户
  (选择金额,customer_name
    来自all_sales
    所有all_sales.salesperson_id = salesperson.id
    按订单金额DESC限制1)
  AS max_sale;

但是,这也行不通。 派生表依赖于 salesperson 表,因此在没有 LATERAL

ERROR 1054(42S22):'where子句'中的未知列'salesperson.id'

添加 LATERAL 关键字会使查询合法:

选择
  salesperson.name,
  max_sale.amount,
  max_sale.customer_name
  营业员,
  - 同时找到最大尺寸和客户
  (选择金额,customer_name
    来自all_sales
    所有all_sales.salesperson_id = salesperson.id
    按订单金额DESC限制1)
  AS max_sale;

简而言之, LATERAL 是刚才讨论的两种方法中所有缺点的有效解决方案。

13.2.11.10子查询错误

有些错误仅适用于子查询。 本节介绍它们。

  • 不支持的子查询语法:

    错误1235(ER_NOT_SUPPORTED_YET)
    SQLSTATE = 42000
    消息=“此版本的MySQL尚不支持
    'LIMIT&IN / ALL / ANY / SOME子查询'“
    

    这意味着MySQL不支持以下形式的语句:

    SELECT * FROM t1 WHERE s1 IN(选择s2 FROM t2 ORDER BY s1 LIMIT 1)
    
  • 子查询中的列数不正确:

    错误1241(ER_OPERAND_COL)
    SQLSTATE = 21000
    Message =“操作数应包含1列”
    

    在这种情况下会发生此错误:

    SELECT(SELECT column1,column2 FROM t2)FROM t1;
    

    如果目的是行比较,则可以使用返回多个列的子查询。 在其他上下文中,子查询必须是标量操作数。 请参见 第13.2.11.5节“行子查询”

  • 子查询中的行数不正确:

    错误1242(ER_SUBSELECT_NO_1_ROW)
    SQLSTATE = 21000
    Message =“子查询返回超过1行”
    

    对于子查询必须最多返回一行但返回多行的语句,会发生此错误。 请考虑以下示例:

    SELECT * FROM t1 WHERE column1 =(SELECT column1 FROM t2);
    

    如果 SELECT column1 FROM t2 只返回一行,则前一个查询将起作用。 如果子查询返回多行,则会发生错误1242。 在这种情况下,查询应该重写为:

    SELECT * FROM t1 WHERE column1 = ANY(SELECT column1 FROM t2);
    
  • 子查询中的表使用不正确:

    错误1093(ER_UPDATE_TABLE_USED)
    SQLSTATE = HY000
    消息=“您无法指定目标表'x'
    用于FROM子句中的更新“
    

    在以下情况下会发生此错误,该错误会尝试修改表并从子查询中的同一个表中进行选择:

    UPDATE t1 SET column2 =(SELECT MAX(column1)FROM t1);
    

    您可以在 UPDATE 语句中 使用子查询进行赋值, 因为子查询在 语句 UPDATE DELETE 语句以及语句中 都是合法的 SELECT 但是,您不能 t1 对子查询 FROM 子句和更新目标 使用相同的表(在本例中

对于事务存储引擎,子查询失败会导致整个语句失败。 对于非事务性存储引擎,将保留在遇到错误之前进行的数据修改。

13.2.11.11优化子查询

开发正在进行中,因此从长远来看,没有优化技巧可靠。 以下列表提供了一些您可能想要使用的有趣技巧。 另请参见 第8.2.2节“优化子查询,派生表,视图引用和公用表表达式”

  • 使用子查询子句影响子查询中行的数量或顺序。 例如:

    SELECT * FROM t1 WHERE t1.column1 IN
      (SELECT column1 FROM t2 ORDER BY column1);
    SELECT * FROM t1 WHERE t1.column1 IN
      (SELECT DISTINCT column1 FROM t2);
    SELECT * FROM t1 WHERE EXISTS
      (SELECT * FROM t2 LIMIT 1);
    
  • 用子查询替换连接。 例如,试试这个:

    SELECT DISTINCT column1 FROM t1 WHERE t1.column1 IN(
      SELECT column1 FROM t2);
    

    而不是这个:

    SELECT DISTINCT t1.column1 FROM t1,t2
      在哪里t1.column1 = t2.column1;
    
  • 某些子查询可以转换为连接,以便与不支持子查询的旧版MySQL兼容。 但是,在某些情况下,将子查询转换为连接可能会提高性能。 请参见 第13.2.11.12节“将子查询重写为连接”

  • 将子句从外部移动到子查询内部。 例如,使用此查询:

    SELECT * FROM t1
      在哪里s1 IN(从s1选择s1 UNION ALL SELECT s1 FROM t2);
    

    而不是这个查询:

    SELECT * FROM t1
      WH1 s1 IN(SELECT s1 FROM t1)或s1 IN(SELECT s1 FROM t2);
    

    再举一个例子,使用这个查询:

    SELECT(SELECT column1 + 5 FROM t1)FROM t2;
    

    而不是这个查询:

    SELECT(SELECT column1 FROM t1)+ 5 FROM t2;
    
  • 使用行子查询而不是相关子查询。 例如,使用此查询:

    SELECT * FROM t1
      WHERE(column1,column2)IN(SELECT column1,column2 FROM t2);
    

    而不是这个查询:

    SELECT * FROM t1
      WHERE EXISTS(SELECT * FROM t2 WHERE t2.column1 = t1.column1
                    AND t2.column2 = t1.column2);
    
  • 使用 NOT (a = ANY (...)) 而不是 a <> ALL (...)

  • 使用 而不是 x = ANY (table containing (1,2)) x=1 OR x=2

  • 使用 = ANY 而不是 EXISTS

  • 对于始终返回一行的不相关子查询, IN 总是慢于 = 例如,使用此查询:

    SELECT * FROM t1
      在哪里t1。col_name=(选择一个FROM t2 WHERE b =some_const);
    

    而不是这个查询:

    SELECT * FROM t1
      在哪里t1。col_nameIN(选择一个FROM t2 WHERE b = some_const);
    

这些技巧可能会导致程序变得更快或更慢。 使用像 BENCHMARK() 函数 这样的MySQL工具 ,你可以了解在你自己的情况下有什么帮助。 请参见 第12.15节“信息功能”

MySQL本身的一些优化是:

  • MySQL只执行一次不相关的子查询。 用于 EXPLAIN 确保给定的子查询确实不相关。

  • MySQL的重写 IN ALL ANY ,和 SOME 子查询,企图采取的是,在子查询选择列表中的列索引的可能性优势。

  • MySQL使用索引查找函数替换以下表单的子查询,该函数 EXPLAIN 描述为特殊的连接类型( unique_subquery index_subquery ):

    ... IN(indexed_columnsingle_table...中选择
  • MySQL使用包含 MIN() 的表达式增强以下表单的表达式 MAX() ,除非 涉及 NULL 值或空集:

    value{ALL | ANY | SOME} {> | <| > = | <=}(uncorrelated subquery

    例如,这个 WHERE 子句:

    在哪里5> ALL(SELECT x FROM t)
    

    优化器可能会像这样对待:

    在哪里5>(SELECT MAX(x)FROM t)
    

另请参阅 MySQL内部:MySQL如何转换子查询

13.2.11.12将子查询重写为连接

有时,除了使用子查询之外,还有其他方法可以测试一组值中的成员资格。 此外,在某些情况下,不仅可以在没有子查询的情况下重写查询,但使用其中一些技术而不是使用子查询可能更有效。 其中一个是 IN() 构造:

例如,这个查询:

SELECT * FROM t1 WHERE id IN(SELECT id FROM t2);

可以改写为:

SELECT DISTINCT t1。* FROM t1,t2 WHERE t1.id = t2.id;

查询:

SELECT * FROM t1 WHERE id NOT IN(SELECT id FROM t2);
SELECT * FROM t1 WHERE NOT EXISTS(SELECT id FROM t2 WHERE t1.id = t2.id);

可以改写为:

SELECT table1。*
  FROM table1 LEFT JOIN table2 ON table1.id = table2.id
  WHERE table2.id IS NULL;

A LEFT [OUTER] JOIN 可以比等效的子查询更快,因为服务器可能能够更好地优化它 - 这一事实并非仅针对MySQL服务器。 在SQL-92之前,外连接不存在,因此子查询是执行某些操作的唯一方法。 今天,MySQL Server和许多其他现代数据库系统提供了广泛的外连接类型。

MySQL Server支持多表 DELETE 语句,可用于根据一个表甚至多个表中的信息同时有效地删除行。 UPDATE 还支持 多表 语句。 请参见 第13.2.2节“删除语法” 第13.2.12节“更新语法”

13.2.12 UPDATE语法

UPDATE 是一个修改表中行的DML语句。

一个 UPDATE 语句可以用开始 WITH 子句来定义内访问的公共表表达式 UPDATE 请参见 第13.2.13节“WITH语法(公用表表达式)”

单表语法:

更新[LOW_PRIORITY] [IGNORE] table_reference
    SET assignment_list
    [WHERE where_condition]
    [订购...]
    [限制row_count]

value
    { expr| 默认}

assignmentcol_name=value

assignment_listassignment[,assignment] ......

多表语法:

更新[LOW_PRIORITY] [IGNORE] table_references
    SET assignment_list
    [WHERE where_condition]

对于单表语法,该 UPDATE 语句使用新值更新指定表中现有行的列。 SET 子句指出要修改的列以及应该给出的值。 每个值都可以作为表达式给出,或者将关键字 DEFAULT 显式设置为默认值。 WHERE 如果给出 子句,则指定标识要更新的行的条件。 如果没有 WHERE 子句,则更新所有行。 如果 ORDER BY 指定了 子句,则按指定的顺序更新行。 LIMIT 子句限制了可以更新的行数。

对于多表语法, UPDATE 更新 table_references 满足条件的 每个表中的行 每个匹配的行都会更新一次,即使它与条件多次匹配也是如此。 对于多表的语法, ORDER BY LIMIT 不能使用。

对于分区表,此语句的单表和多表形式都支持将 PARTITION 选项用作表引用的一部分。 此选项采用一个或多个分区或子分区(或两者)的列表。 仅检查列出的分区(或子分区)是否匹配,并且不更新任何这些分区或子分区中的行,无论它是否满足 where_condition

注意

与使用时的情况 PARTITION 有一个 INSERT REPLACE 声明,一个非常有效的 UPDATE ... PARTITION 声明被认为是成功的,即使在列出的分区(或子)没有行匹配 where_condition

有关更多信息和示例,请参见 第23.5节“分区选择”

where_condition 是一个表达式,对于要更新的​​每一行,计算结果为true。 有关表达式语法,请参见 第9.5节“表达式”

table_references 并按 第13.2.10节“SELECT语法” where_condition 中的说明进行指定

UPDATE 需要 UPDATE 为实际更新的 列中引用的列提供权限 您只需要 SELECT 读取但未修改的任何列 权限。

UPDATE 语句支持以下修饰符:

  • 使用 LOW_PRIORITY 修饰符, UPDATE 延迟 执行, 直到没有其他客户端从表中读取。 这会影响只使用表级锁只存储引擎(例如 MyISAM MEMORY MERGE )。

  • 使用 IGNORE 修饰符,即使在更新期间发生错误,update语句也不会中止。 不更新在唯一键值上发生重复键冲突的行。 更新为导致数据转换错误的值的行将更新为最接近的有效值。 有关更多信息,请参阅 IGNORE关键字和严格SQL模式的比较

UPDATE IGNORE 语句(包括具有 ORDER BY 子句的语句)被标记为基于语句的复制不安全。 (这是因为更新行的顺序决定了哪些行被忽略。)这些语句在使用基于语句的模式时在错误日志中产生警告,并在使用 MIXED 模式 时使用基于行的格式写入二进制日志 (Bug#11758262,Bug#50439)有关详细 信息, 请参见 第17.2.1.3节“二进制日志记录中安全和不安全语句的确定”

如果从表中访问要在表达式中更新 UPDATE 的列 ,请 使用列的当前值。 例如,以下语句设置 col1 为比其当前值多一个:

更新t1 SET col1 = col1 + 1;

以下语句中的第二个赋值设置 col2 为当前(更新的) col1 值,而不是原始 col1 值。 结果就是 col1 并且 col2 具有相同的值。 此行为与标准SQL不同。

UPDATE t1 SET col1 = col1 + 1,col2 = col1;

单表 UPDATE 分配通常从左到右进行评估。 对于多表更新,无法保证以任何特定顺序执行分配。

如果将列设置为当前具有的值,MySQL会注意到这一点并且不会更新它。

如果更新已 NOT NULL 通过设置为 声明的列,则在 NULL 启用严格SQL模式时会发生错误; 否则,将列设置为列数据类型的隐式默认值,并增加警告计数。 隐式默认值 0 用于数字类型,空字符串( '' )用于字符串类型, 值用于日期和时间类型。 请参见 第11.7节“数据类型默认值”

如果显式更新生成的列,则唯一允许的值为 DEFAULT 有关生成的列的信息,请参见 第13.1.20.9节“创建表和生成的列”

UPDATE 返回实际更改的行数。 mysql_info() C API函数返回被匹配和更新的行数,并在发生警告的数量 UPDATE

您可以 用来限制范围 子句是行匹配限制。 一旦找到 满足该 子句的 行, 该语句就会停止 ,无论它们是否实际被更改。 LIMIT row_count UPDATE LIMIT row_count WHERE

如果 UPDATE 语句包含 ORDER BY 子句,则按照子句指定的顺序更新行。 这在某些可能导致错误的情况下非常有用。 假设一个表 t 包含一个 id 具有唯一索引 的列 以下语句可能会因重复键错误而失败,具体取决于更新行的顺序:

UPDATE t SET id = id + 1;

例如,如果表中的 id 包含1和2, 并且在2更新为3之前1更新为2,则会发生错误。 要避免此问题,请添加一个 ORDER BY 子句以使具有较大 id 的行在具有较小 的行 之前更新:

UPDATE t SET id = id + 1 ORDER BY id DESC;

您还可以执行 UPDATE 涵盖多个表的操作。 但是,您不能使用 ORDER BY LIMIT 使用多表 UPDATE table_references 子句列出了连接中涉及的表。 其语法在 第13.2.10.2节“JOIN语法”中描述 这是一个例子:

更新项目,月份SET items.price = month.price
WHERE items.id = month.id;

前面的示例显示了使用逗号运算符的内部联接,但多表 UPDATE 语句可以使用语句中允许的任何类型的联接 SELECT ,例如 LEFT JOIN

如果您使用 UPDATE 涉及 InnoDB 具有外键约束 的表的多表 语句 ,则MySQL优化器可能会按照与其父/子关系不同的顺序处理表。 在这种情况下,语句失败并回滚。 相反,更新单个表并依赖提供的 ON UPDATE 功能, InnoDB 以便相应地修改其他表。 请参见 第15.6.1.5节“InnoDB和FOREIGN KEY约束”

您无法更新表并从子查询中的同一表中进行选择。

一个 UPDATE 使用的存储引擎,诸如分区表 MyISAM ,其使用表级锁锁只有那些含有匹配的行的分区 UPDATE 声明 WHERE 子句,只要没有表分区的列被更新的。 (对于 InnoDB 使用行级锁定的 存储引擎 ,不会发生分区锁定。)有关更多信息,请参阅 分区和锁定

13.2.13 WITH语法(公用表表达式)

公用表表达式(CTE)是一个命名的临时结果集,它存在于单个语句的范围内,并且可以在该语句中稍后引用,可能多次。 以下讨论描述了如何编写使用CTE的语句。

有关CTE优化的信息,请参见 第8.2.2.4节“使用合并或实现优化派生表,视图引用和公用表表达式”

其他资源

这些文章包含有关在MySQL中使用CTE的其他信息,包括许多示例:

公用表表达式语法

要指定公用表表达式,请使用 WITH 具有一个或多个逗号分隔子句的子句。 每个子条款都提供一个子查询,用于生成结果集,并将名称与子查询相关联。 下面的示例定义名为的CTE cte1 cte2 WITH 子句,并且是指在它们的顶层 SELECT 下面的 WITH 子句:

WITH
  cte1 AS(SELECT a,b FROM table1),
  cte2 AS(SELECT c,d FROM table2)
SELECT b,d FROM cte1 JOIN cte2
WHERE cte1.a = cte2.c;

在包含该 WITH 子句 的语句中 ,可以引用每个CTE名称以访问相应的CTE结果集。

CTE名称可以在其他CTE中引用,从而可以基于其他CTE定义CTE。

CTE可以引用自身来定义递归CTE。 递归CTE的常见应用包括分层或树状结构数据的序列生成和遍历。

公用表表达式是DML语句语法的可选部分。 它们使用以下 WITH 子句 定义

with_clause
    带[RECURSIVE]
        cte_name[(col_name[,col_name] ...)] AS(subquery
        [,cte_name[(col_name[,col_name] ...)] AS(subquery)] ......

cte_name 命名单个公用表表达式,可以在包含该 WITH 子句 的语句中用作表引用

subquery 部分 被称为 CTE的子查询 ,它是产生CTE结果集的原因。 以下括号 是必需的。 AS (subquery) AS

如果公用表表达式的子查询引用自己的名称,则表达式是递归的。 RECURSIVE 关键字必须被包含,如果任何的CTE的 WITH 条款是递归的。 有关更多信息,请参阅 递归公用表表达式

确定给定CTE的列名如下:

  • 如果带括号的名称列表遵循CTE名称,则这些名称是列名称:

    与cte(col1,col2)AS
      选择1,2
      UNION ALL
      选择3,4
    SELECT col1,col2 FROM cte;
    

    列表中的名称数必须与结果集中的列数相同。

  • 否则,列名来自首的选择列表中 SELECT 的内 部分: AS (subquery)

    与cte AS
      SELECT 1 AS col1,2 AS col2
      UNION ALL
      选择3,4
    SELECT col1,col2 FROM cte;
    

WITH 在这些情况下允许 使用 条款:

  • 在开始时 SELECT UPDATE DELETE 语句。

    WITH ... SELECT ...
    WITH ... UPDATE ...
    WITH ...删除...
    
  • 在子查询的开头(包括派生表子查询):

    SELECT ... WHERE id IN(WITH ... SELECT ...)...
    SELECT * FROM(WITH ... SELECT ...)AS dt ...
    
  • 紧接 SELECT 在包含 SELECT 声明的语句之前:

    INSERT ... WITH ... SELECT ...
    更换......用...选择......
    CREATE TABLE ... WITH ... SELECT ...
    创建视图... ... ...选择...
    DECLARE CURSOR ... WITH ... SELECT ...
    EXPLAIN ... WITH ... SELECT ...
    

WITH 在同一级别 允许 一个 条款。 WITH 随后 WITH 在同一水平是不允许的,所以这是非法的:

WITH cte1 AS(...)WITH cte2 AS(...)SELECT ...

要使语句合法,请使用单个 WITH 子句以逗号分隔子句:

使用cte1 AS(...),cte2 AS(...)SELECT ...

但是,如果语句 WITH 出现在不同级别 ,则语句可以包含多个 子句:

使用cte1 AS(SELECT 1)
SELECT * FROM(WITH cte2 AS(SELECT 2)SELECT * FROM cte2 JOIN cte1)AS dt;

一个 WITH 子句可以定义一个或多个公用表表达式,但每个CTE名称必须是唯一的条款。 这是非法的:

使用cte1 AS(...),cte1 AS(...)SELECT ...

要使语句合法,请使用唯一名称定义CTE:

使用cte1 AS(...),cte2 AS(...)SELECT ...

CTE可以指自己或其他CTE:

  • 自引用CTE是递归的。

  • CTE可以引用同一 WITH 子句中 前面定义的CTE ,但不能 引用 后面定义的 CTE

    该约束排除了相互递归的CTE,其中 cte1 引用 cte2 cte2 引用 cte1 其中一个引用必须是稍后定义的CTE,这是不允许的。

  • 给定查询块中的CTE可以引用在更外层的查询块中定义的CTE,但不是在更内层的查询块中定义的CTE。

为了解析对具有相同名称的对象的引用,派生表隐藏了CTE; 和CTE隐藏基表, TEMPORARY 表和视图。 通过在同一查询块中搜索对象,然后在没有找到具有该名称的对象的情况下依次前进到外部块来进行名称解析。

与派生表一样,CTE在MySQL 8.0.14之前不能包含外部引用。 这是在MySQL 8.0.14中解除的MySQL限制,而不是SQL标准的限制。 有关递归CTE特有的其他语法注意事项,请参阅 递归公用表表达式

递归公用表表达式

递归公用表表达式是具有引用其自己名称的子查询的表达式。 例如:

WITH RECURSIVE cte(n)AS
  选择1
  UNION ALL
  SELECT n + 1 FROM cte WHERE n <5
SELECT * FROM cte;

执行时,语句生成此结果,包含简单线性序列的单个列:

+ ------ +
| n |
+ ------ +
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+ ------ +

递归CTE具有以下结构:

  • 如果 WITH 条款中的 WITH RECURSIVE 任何CTE WITH 引用自身 条款必须以 条款开头 (如果CTE没有提及, RECURSIVE 则允许但不要求。)

    如果您忘记 RECURSIVE 了递归CTE,则可能会出现此错误:

    ERROR 1146(42S02):表' cte_name'不存在
    
  • 递归CTE子查询有两个部分,由 UNION [ALL] 分隔 UNION DISTINCT

    SELECT ...  - 返回初始行集
    UNION ALL
    SELECT ...  - 返回其他行集
    

    第一个 SELECT 产生CTE的初始行或不引用CTE名称。 第二个 SELECT 通过引用其 FROM 子句中 的CTE名称来生成其他行和递归 当此部分不产生新行时,递归结束。 因此,递归CTE由非递归 SELECT 部分和递归 SELECT 部分组成。

    每个 SELECT 部分本身可以是多个 SELECT 语句 的联合

  • CTE结果列的类型 SELECT 仅从 非递归 部分 的列类型推断 ,并且列都可以为空。 对于类型确定,将 SELECT 忽略 递归 部分。

  • 如果非递归和递归部分被分开 UNION DISTINCT ,则消除重复的行。 这对于执行传递闭包的查询很有用,可以避免无限循环。

  • 递归部分的每次迭代仅对前一次迭代产生的行进行操作。 如果递归部分具有多个查询块,则以未指定的顺序调度每个查询块的迭代,并且每个查询块对由其先前迭代或自上一次迭代结束以来的其他查询块产生的行进行操作。

前面显示的递归CTE子查询具有这个非递归部分,它检索单个行以生成初始行集:

选择1

CTE子查询也有这个递归部分:

SELECT n + 1 FROM cte WHERE n <5

在每次迭代时,会 SELECT 生成一个行,其值大于 n 前一行集 的值 第一次迭代对初始行set( 1 )进行操作并生成 1+1=2 ; 第二次迭代在第一次迭代的行set( 2 )上运行并产生 2+1=3 ; 等等。 这一直持续到递归结束,当 n 不再小于5 时发生递归

如果CTE的递归部分为列生成比非递归部分更宽的值,则可能需要加宽非递归部分中的列以避免数据截断。 请考虑以下声明:

与RECURSIVE cte AS
  SELECT 1 AS n,'abc'AS str
  UNION ALL
  SELECT n + 1,CONCAT(str,str)FROM cte WHERE n <3
SELECT * FROM cte;

在非严格SQL模式下,该语句生成此输出:

+ ------ + ------ +
| n | str |
+ ------ + ------ +
| 1 | abc |
| 2 | abc |
| 3 | abc |
+ ------ + ------ +

str 列值都是 'abc' 因为非递归 SELECT 确定列宽。 因此, str 递归产生 的更宽的 SELECT 被截断。

在严格的SQL模式下,该语句会产生错误:

ERROR 1406(22001):第1行的列'str'的数据太长

要解决此问题,以便语句不会产生截断或错误,请 CAST() 在nonrecursive中 使用 SELECT 以使 str 列更宽:

与RECURSIVE cte AS
  SELECT 1 AS n,CAST('abc'AS CHAR(20))AS str
  UNION ALL
  SELECT n + 1,CONCAT(str,str)FROM cte WHERE n <3
SELECT * FROM cte;

现在语句产生了这个结果,没有截断:

+ ------ + -------------- +
| n | str |
+ ------ + -------------- +
| 1 | abc |
| 2 | abcabc |
| 3 | abcabcabcabc |
+ ------ + -------------- +

列是按名称而不是位置访问的,这意味着递归部分中的列可以访问非递归部分中具有不同位置的列,如此CTE所示:

与RECURSIVE cte AS
  SELECT 1 AS n,1 AS p,-1 AS q
  UNION ALL
  SELECT n + 1,q * 2,p * 2 FROM cte WHERE n <5
SELECT * FROM cte;

因为 p 在一行中派生自 q 前一行,反之亦然,正值和负值在输出的每个连续行中交换位置:

+ ------ + ------ + ------ +
| n | p | q |
+ ------ + ------ + ------ +
| 1 | 1 | -1 |
| 2 | -2 | 2 |
| 3 | 4 | -4 |
| 4 | -8 | 8 |
| 5 | 16 | -16 |
+ ------ + ------ + ------ +

一些语法约束适用于递归CTE子查询:

  • 递归 SELECT 部分不得包含以下结构:

    • 聚合函数如 SUM()

    • 窗口功能

    • GROUP BY

    • ORDER BY

    • LIMIT

    • DISTINCT

    此约束不适用于 SELECT 递归CTE 的非递归 部分。 该禁令 DISTINCT 仅适用于 UNION 会员; UNION DISTINCT 是允许的。

  • 递归 SELECT 部分必须仅引用CTE一次且仅在其 FROM 子句中 引用 ,而不是在任何子查询中 引用 它可以引用CTE以外的表,并将它们与CTE连接起来。 如果在这样的连接中使用,则CTE不能位于a的右侧 LEFT JOIN

这些约束来自于SQL标准,比其他的MySQL特定的排除 ORDER BY LIMIT DISTINCT

对于递归CTE, EXPLAIN 递归 SELECT 部分的 输出行 显示 Recursive Extra 列中。

显示的成本估算 EXPLAIN 表示每次迭代的成本,这可能与总成本有很大差异。 优化程序无法预测迭代次数,因为它无法预测 WHERE 子句何时变为false。

CTE实际成本也可能受结果集大小的影响。 产生许多行的CTE可能需要一个足够大的内部临时表,以便从内存转换为磁盘格式,并且可能会受到性能损失。 如果是这样,增加允许的内存临时表大小可以提高性能; 请参见 第8.4.4节“MySQL中的内部临时表使用”

限制公用表表达式递归

对于递归CTE来说,递归 SELECT 部分包括终止递归的条件 是很重要的 作为防止失控递归CTE的开发技术,您可以通过限制执行时间来强制终止:

  • cte_max_recursion_depth 系统变量强制对CTE的递归水平的数量限制。 服务器终止执行任何CTE,该CTE递归的级别高于此变量的值。

  • 所述 max_execution_time 系统变量强制用于执行超时 SELECT 在当前会话中执行的语句。

  • MAX_EXECUTION_TIME 优化器提示强制为每个查询执行超时 SELECT 在它出现的语句。

假设错误地写入递归CTE而没有递归执行终止条件:

WITH RECURSIVE cte(n)AS
  选择1
  UNION ALL
  SELECT n + 1 FROM cte
SELECT * FROM cte;

默认情况下, cte_max_recursion_depth 其值为1000,导致CTE在递归过去1000级时终止。 应用程序可以更改会话值以根据其要求进行调整:

SET SESSION cte_max_recursion_depth = 10;  - 只允许浅递归
SET SESSION cte_max_recursion_depth = 1000000;  - 允许更深层次的递归

您还可以设置全局 cte_max_recursion_depth 值以影响随后开始的所有会话。

对于执行缓慢递归或在有理由将 cte_max_recursion_depth 设置得 非常高的 上下文中的查询, 防止深度递归的另一种方法是设置每会话超时。 为此,在执行CTE语句之前执行如下语句:

SET max_execution_time = 1000;  - 施加一秒钟超时

或者,在CTE语句本身中包含优化器提示:

WITH RECURSIVE cte(n)AS
  选择1
  UNION ALL
  SELECT n + 1 FROM cte
SELECT / * + MAX_EXECUTION_TIME(1000)* / * FROM cte;

如果没有执行时间限制的递归查询进入无限循环,则可以使用另一个会话终止它 KILL QUERY 在会话本身内,用于运行查询的客户端程序可能提供一种终止查询的方法。 例如,在 mysql中 ,键入 Control + C会 中断当前语句。

递归公用表表达式示例

如前所述,递归公用表表达式(CTE)经常用于序列生成和遍历分层或树结构数据。 本节介绍这些技术的一些简单示例。

斐波纳契系列生成

Fibonacci系列以两个数字0和1(或1和1)开头,之后的每个数字是前两个数字的总和。 如果递归生成的每一行都 SELECT 可以访问该系列中的前两个数字,则 递归公用表表达式可以生成Fibonacci 系列。 以下CTE使用0和1作为前两个数字生成10个数字系列:

WITH RECURSIVE fibonacci(n,fib_n,next_fib_n)AS
  SELECT 1,0,1
  UNION ALL
  SELECT n + 1,next_fib_n,fib_n + next_fib_n
    来自斐波纳契,其中n <10
SELECT * FROM fibonacci;

CTE产生这样的结果:

+ ------ + ------- + ------------ +
| n | fib_n | next_fib_n |
+ ------ + ------- + ------------ +
| 1 | 0 | 1 |
| 2 | 1 | 1 |
| 3 | 1 | 2 |
| 4 | 2 | 3 |
| 5 | 3 | 5 |
| 6 | 5 | 8 |
| 7 | 8 | 13 |
| 8 | 13 | 21 |
| 9 | 21 | 34 |
| 10 | 34 | 55 |
+ ------ + ------- + ------------ +

CTE如何运作:

  • n 是一个显示列,表示该行包含 n 第-Fibonacci数。 例如,第8个斐波纳契数是13。

  • fib_n 列显示斐波纳契数 n

  • next_fib_n 列显示编号后的下一个斐波纳契数 n 此列为下一行提供下一个系列值,以便该行可以在其 fib_n 列中 生成前两个系列值的总和

  • n 到达10 时递归结束 。这是一个任意选择,将输出限制为一小组行。

前面的输出显示了整个CTE结果。 要仅选择其中的一部分,请 WHERE 在顶级 添加适当的 子句 SELECT 例如,要选择第8个Fibonacci数,请执行以下操作:

MySQL的> WITH RECURSIVE fibonacci ...
       ...
       SELECT fib_n FROM fibonacci WHERE n = 8;
+ ------- +
| fib_n |
+ ------- +
| 13 |
+ ------- +
日期系列生成

公用表表达式可以生成一系列连续日期,这对于生成包含系列中所有日期的行的摘要非常有用,包括未在汇总数据中表示的日期。

假设销售数字表包含以下行:

MySQL的> SELECT * FROM sales ORDER BY date, price;
+ ------------ + -------- +
| 日期| 价格|
+ ------------ + -------- +
| 2017-01-03 | 100.00 |
| 2017-01-03 | 200.00 |
| 2017-01-06 | 50.00 |
| 2017-01-08 | 10.00 |
| 2017-01-08 | 20.00 |
| 2017-01-08 | 150.00 |
| 2017-01-10 | 5.00 |
+ ------------ + -------- +

此查询总结了每天的销售额:

MySQL的> SELECT date, SUM(price) AS sum_price
       FROM sales
       GROUP BY date
       ORDER BY date;
+ ------------ + ----------- +
| 日期| sum_price |
+ ------------ + ----------- +
| 2017-01-03 | 300.00 |
| 2017-01-06 | 50.00 |
| 2017-01-08 | 180.00 |
| 2017-01-10 | 5.00 |
+ ------------ + ----------- +

但是,该结果包含 未在表格跨越的日期范围中表示的日期的 可以使用递归CTE生成表示范围中所有日期的结果,以生成该组日期,并与a连接 LEFT JOIN 与销售数据相结合。

以下是生成日期范围系列的CTE:

WITH RECURSIVE日期(日期)AS
  SELECT MIN(日期)FROM销售
  UNION ALL
  选择日期+间隔日期1天
  WHERE日期+ INTERVAL 1 DAY <=(SELECT MAX(date)FROM sales)
SELECT * FROM dates;

CTE产生这样的结果:

+ ------------ +
| 日期|
+ ------------ +
| 2017-01-03 |
| 2017-01-04 |
| 2017-01-05 |
| 2017-01-06 |
| 2017-01-07 |
| 2017-01-08 |
| 2017-01-09 |
| 2017-01-10 |
+ ------------ +

CTE如何运作:

  • 非递归 SELECT 产生 sales 表格 跨越的日期范围中的最低日期

  • 递归生成的每一行将 SELECT 一天添加到前一行生成的日期。

  • 在日期到达 sales 表所 跨越的日期范围中的最高日期之后,递归结束

用加入CTE LEFT JOIN sales 表产生与一排范围内的每个日期的销售汇总:

WITH RECURSIVE日期(日期)AS
  SELECT MIN(日期)FROM销售
  UNION ALL
  选择日期+间隔日期1天
  WHERE日期+ INTERVAL 1 DAY <=(SELECT MAX(date)FROM sales)
SELECT dates.date,COALESCE(SUM(price),0)AS sum_price
FROM日期LEFT JOIN销售日期date.date = sales.date
GROUP BY dates.date
ORDER BY dates.date;

输出如下所示:

+ ------------ + ----------- +
| 日期| sum_price |
+ ------------ + ----------- +
| 2017-01-03 | 300.00 |
| 2017-01-04 | 0.00 |
| 2017-01-05 | 0.00 |
| 2017-01-06 | 50.00 |
| 2017-01-07 | 0.00 |
| 2017-01-08 | 180.00 |
| 2017-01-09 | 0.00 |
| 2017-01-10 | 5.00 |
+ ------------ + ----------- +

有些要点需要注意:

  • 查询是否效率低下,尤其 MAX() 是递归中每行执行子查询的查询 SELECT 检查 EXPLAIN 显示子查询已经过优化以提高效率。

  • 使用 COALESCE() 避免 NULL sum_price 列中 显示 sales 表中 没有销售数据的日期

分层数据遍历

递归公用表表达式对于遍历形成层次结构的数据非常有用。 考虑这些创建小数据集的语句,该数据集为公司中的每个员工显示员工姓名和ID号以及员工经理的ID。 顶级员工(CEO)的经理ID为 NULL (无经理)。

CREATE TABLE员工(
  id INT PRIMARY KEY NOT NULL,
  name VARCHAR(100)NOT NULL,
  manager_id INT NULL,
  INDEX(manager_id),
FOREIGN KEY(manager_id)REFERENCES EMPLOYEES(id)
);
插入员工价值观
(333,“Yasmina”,NULL),#Yasmina是CEO(manager_id为NULL)
(198,“John”,333),#John的身份证号为198,并向333报告(Yasmina)
(692,“Tarek”,333),
(29,“Pedro”,198),
(4610,“莎拉”,29),
(72,“皮埃尔”,29),
(123,“Adil”,692);

结果数据集如下所示:

MySQL的> SELECT * FROM employees ORDER BY id;
+ ------ + --------- + ------------ +
| id | 名字| manager_id |
+ ------ + --------- + ------------ +
| 29 | 佩德罗| 198 |
| 72 | 皮埃尔| 29 |
| 123 | Adil | 692 |
| 198 | 约翰| 333 |
| 333 | Yasmina | NULL |
| 692 | Tarek | 333 |
| 4610 | 莎拉| 29 |
+ ------ + --------- + ------------ +

要使用每个员工的管理链(即从CEO到员工的路径)生成组织结构图,请使用递归CTE:

WITH RECURSIVE employee_paths(id,name,path)AS
  SELECT id,name,CAST(id AS CHAR(200))
    来自员工
    WHERE manager_id为NULL
  UNION ALL
  SELECT e.id,e.name,CONCAT(ep.path,',',e.id)
    FROM employee_paths AS ep JOIN员工AS e
      在ep.id = e.manager_id上
SELECT * FROM employee_paths ORDER BY路径;

CTE产生这个输出:

+ ------ + --------- + ----------------- +
| id | 名字| 路径|
+ ------ + --------- + ----------------- +
| 333 | Yasmina | 333 |
| 198 | 约翰| 333,198 |
| 29 | 佩德罗| 333,198,29 |
| 4610 | 莎拉| 333,198,29,4610 |
| 72 | 皮埃尔| 333,198,29,72 |
| 692 | Tarek | 333,692 |
| 123 | Adil | 333,692,123 |
+ ------ + --------- + ----------------- +

CTE如何运作:

  • 非递归 SELECT 产生CEO的行(带有一行的行) NULL 经理ID

    path 列被扩展为 CHAR(200) 以确保 path 递归所产生 的较长 值的空间 SELECT

  • 递归生成的每一行都会 SELECT 查找直接向前一行生成的员工报告的所有员工。 对于每个此类员工,该行包括员工ID和名称以及员工管理链。 该链是经理的链条,员工ID添加到最后。

  • 当员工没有其他人向他们报告时,递归就结束了。

要查找特定员工或员工的路径,请 WHERE 在顶级 添加 子句 SELECT 例如,要显示Tarek和Sarah的结果,请 SELECT 像这样 修改

MySQL的> WITH RECURSIVE ...
       ...
       SELECT * FROM employees_extended
       WHERE id IN (692, 4610)
       ORDER BY path;
+ ------ + ------- + ----------------- +
| id | 名字| 路径|
+ ------ + ------- + ----------------- +
| 4610 | 莎拉| 333,198,29,4610 |
| 692 | Tarek | 333,692 |
+ ------ + ------- + ----------------- +

公用表表达式与类似构造的比较

公用表表达式(CTE)在某些方面类似于派生表:

  • 两个结构都被命名。

  • 这两种结构都存在于单个语句的范围内。

由于这些相似性,CTE和派生表通常可以互换使用。 作为一个简单的例子,这些陈述是等价的:

WITH cte AS(SELECT 1)SELECT * FROM cte;
SELECT * FROM(SELECT 1)AS dt;

但是,CTE比派生表有一些优势:

  • 派生表只能在查询中一次引用。 CTE可以多次引用。 要使用派生表结果的多个实例,必须多次派生结果。

  • CTE可以是自引用(递归)。

  • 一个CTE可以引用另一个。

  • 当CTE的定义出现在语句的开头而不是嵌入其中时,CTE可能更容易阅读。

CTE类似于使用 CREATE [TEMPORARY] TABLE 但不需要显式定义或删除的表。 对于CTE,您无需创建表的权限。

13.3交易和锁定声明

MySQL支持通过语句,如本地事务(一个给定的客户端会话内) SET autocommit START TRANSACTION COMMIT ,和 ROLLBACK 请参见 第13.3.1节“START TRANSACTION,COMMIT和ROLLBACK语法” XA事务支持也使MySQL能够参与分布式事务。 请参见 第13.3.8节“XA事务”

13.3.1 START TRANSACTION,COMMIT和ROLLBACK语法

开始交易
    [ transaction_characteristic[,transaction_characteristic] ......]

transaction_characteristic:{
    一致的快照
  | 读写
  | 只读
}

开始[工作]
COMMIT [WORK] [和[NO] CHAIN] [[NO] RELEASE]
ROLLBACK [WORK] [和[NO] CHAIN] [[NO] RELEASE]
SET autocommit = {0 | 1}

这些陈述提供对 交易 使用的控制

  • START TRANSACTION BEGIN 开始新的交易。

  • COMMIT 提交当前事务,使其更改永久化。

  • ROLLBACK 回滚当前事务,取消其更改。

  • SET autocommit 禁用或启用当前会话的默认自动提交模式。

默认情况下,MySQL在 启用 自动提交 模式的 情况下运行 这意味着只要执行更新(修改)表的语句,MySQL就会将更新存储在磁盘上以使其永久化。 无法回滚更改。

要为一系列语句隐式禁用自动提交模式,请使用 START TRANSACTION 语句:

开始交易;
SELECT @A:= SUM(薪水)FROM table1 WHERE type = 1;
UPDATE table2 SET summary = @ A WHERE type = 1;
承诺;

使用 START TRANSACTION ,自动提交保持禁用状态,直到您使用 COMMIT 结束事务 ROLLBACK 然后,自动提交模式将恢复为先前的状态。

START TRANSACTION 允许几个控制交易特征的修饰符。 要指定多个修饰符,请用逗号分隔它们。

  • WITH CONSISTENT SNAPSHOT 修正开始 一致读取 存储引擎,能够它。 这仅适用于 InnoDB 效果与 从任何 发出a START TRANSACTION 后跟a 相同 请参见 第15.7.2.3节“一致的非锁定读取” 修改不改变当前的事务 隔离级别 ,所以它提供了一个一致的快照仅在当前隔离级别是一个允许连续读取。 允许一致读取的唯一隔离级别是 对于所有其他隔离级别, SELECT InnoDB WITH CONSISTENT SNAPSHOT REPEATABLE READ WITH CONSISTENT SNAPSHOT 子句被忽略。 时会生成警告 WITH CONSISTENT SNAPSHOT 子句被忽略。

  • READ WRITE READ ONLY 修饰符设置事务访问模式。 它们允许或禁止更改交易中使用的表格。 READ ONLY 限制可防止事务修改或锁定对其他事务可见的事务和非事务表; 事务仍然可以修改或锁定临时表。

    InnoDB 当事务已知为只读时, MySQL可以对 表的 查询进行额外的优化 指定 READ ONLY 确保在无法自动确定只读状态的情况下应用这些优化。 有关 更多信息 请参见 第8.5.3节“优化InnoDB只读事务”

    如果未指定访问模式,则应用默认模式。 除非更改了默认值,否则它是可读/写的。 它不允许同时指定 READ WRITE ,并 READ ONLY 在同一语句。

    在只读模式下,仍然可以更改使用。创建的表 TEMPORARY 使用DML语句 关键字 表。 与永久表一样,不允许使用DDL语句进行更改。

    有关事务访问模式的其他信息,包括更改默认模式的方法,请参见 第13.3.7节“SET TRANSACTION语法”

    如果 read_only 启用 系统变量,则显式启动事务 START TRANSACTION READ WRITE 需要 CONNECTION_ADMIN SUPER 权限。

重要

用于编写MySQL客户端应用程序(例如JDBC)的许多API提供了自己的方法来启动可以(有时应该)使用而不是 START TRANSACTION 从客户端 发送 语句的 事务 请参见 第28章, 连接器和API 更多信息 的文档。

要显式禁用自动提交模式,请使用以下语句:

SET autocommit = 0;

通过将 autocommit 变量 设置 为零来 禁用自动提交模式后 ,对事务安全表(例如 InnoDB or或 表)的更改 NDB 不会立即成为永久 更改 您必须使用 COMMIT 将更改存储到磁盘或 ROLLBACK 忽略更改。

autocommit 是一个会话变量,必须为每个会话设置。 要禁用自动提交模式为每个新连接,看到的描述 autocommit 在系统变量 第5.1.8节,“服务器系统变量”

BEGIN BEGIN WORK 作为 START TRANSACTION 启动事务的 别名支持 START TRANSACTION 是标准的SQL语法,是启动ad-hoc事务的推荐方法,并允许使用修饰符 BEGIN 不具有的

BEGIN 语句不同于使用 BEGIN 启动 BEGIN ... END 复合语句 关键字 后者不会开始交易。 请参见 第13.6.1节“BEGIN ... END复合语句语法”

注意

在所有存储的程序(存储过程和函数,触发器和事件)中,解析器将其 BEGIN [WORK] 视为 BEGIN ... END 的开头 START TRANSACTION 相反, 在此上下文中开始一个事务

以及和 子句 一样 WORK 支持 可选 关键字 可用于在事务完成额外控制。 系统变量 的值 确定默认的完成行为。 请参见 第5.1.8节“服务器系统变量” COMMIT ROLLBACK CHAIN RELEASE CHAIN RELEASE completion_type

AND CHAIN 子句导致新事务在当前事务结束后立即开始,并且新事务与刚刚终止的事务具有相同的隔离级别。 新事务还使用与 刚刚终止的事务 相同的访问模式( READ WRITE READ ONLY )。 RELEASE 子句使服务器在终止当前事务后断开当前客户端会话。 包括 NO 关键字抑制 CHAIN RELEASE 完成,如果 completion_type 系统变量设置为默认情况下导致链接或释放完成 ,这可能很有用

开始事务会导致提交任何挂起的事务。 有关 更多信息 请参见 第13.3.3节“导致隐式提交的语句”

开始事务还会导致获取的表锁 LOCK TABLES 被释放,就像您已执行一样 UNLOCK TABLES 开始事务不会释放获取的全局读锁 FLUSH TABLES WITH READ LOCK

为获得最佳结果,应仅使用由单个事务安全存储引擎管理的表来执行事务。 否则,可能会出现以下问题:

  • 如果您使用来自多个事务安全存储引擎(例如 InnoDB )的表,而事务隔离级别不是 SERIALIZABLE ,那么当一个事务提交时,另一个使用相同表的正在进行的事务可能只会看到一些更改由第一笔交易制作。 也就是说,混合引擎无法保证事务的原子性,并且可能导致不一致。 (如果混合引擎事务很少发生,您可以 根据需要在每个事务的基础上 SET TRANSACTION ISOLATION LEVEL 设置隔离级别 SERIALIZABLE 。)

  • 如果在事务中使用非事务安全的表,则无论自动提交模式的状态如何,都会立即存储对这些表的更改。

  • 如果 ROLLBACK 在更新事务中的非事务表后 发出 语句,则会 ER_WARNING_NOT_COMPLETE_ROLLBACK 发出警告。 将回滚对事务安全表的更改,但不会更改对非事务安全表的更改。

每个事务都存储在二进制日志中的一个块中 COMMIT 回滚的事务不会被记录。 例外 :修改到非事务性表不能被回滚如果被回滚的事务包括修改非事务性表,则整个事务与记录 ROLLBACK 在结束语句,以确保修改到非事务性表被复制)。请参见 第5.4.4,“二进制日志”

您可以使用该 SET TRANSACTION 语句 更改事务的隔离级别或访问模式 请参见 第13.3.7节“SET TRANSACTION语法”

回滚可能是一种缓慢的操作,可能会在没有用户明确要求的情况下隐式发生(例如,发生错误时)。 因此, 会话列中 SHOW PROCESSLIST 显示 ,不仅用于使用 语句 执行的显式回滚, 还用于隐式回滚。 Rolling back State ROLLBACK

注意

在MySQL 8.0, , BEGIN COMMIT ROLLBACK 不受 --replicate-do-db --replicate-ignore-db 规则。

13.3.2无法回滚的陈述

某些语句无法回滚。 通常,这些语句包括数据定义语言(DDL)语句,例如创建或删除数据库的语句,创建,删除或更改表或存储例程的语句。

您应该将交易设计为不包括此类声明。 如果您在无法回滚的事务中提前发出语句,然后另一个语句失败,则在这种情况下,通过发出 ROLLBACK 语句 无法回滚事务的完整效果

13.3.3导致隐式提交的语句

本节中列出的语句(以及它们的任何同义词)隐式结束当前会话中活动的任何事务,就像您 COMMIT 在执行语句之前 完成了 一样。

大多数这些语句在执行后也会导致隐式提交。 目的是在自己的特殊交易中处理每个这样的陈述。 事务控制和锁定语句是例外:如果在执行之前发生隐式提交,则之后不会发生另一次提交。

13.3.4 SAVEPOINT,ROLLBACK到SAVEPOINT和RELEASE SAVEPOINT语法

SAVEPOINT identifier
ROLLBACK [WORK]到[SAVEPOINT] identifier
发布SAVEPOINTidentifier

InnoDB 支持SQL语句 SAVEPOINT ROLLBACK TO SAVEPOINT RELEASE SAVEPOINT 以及可选 WORK 关键字 ROLLBACK

SAVEPOINT 语句设置名为的命名事务保存点 identifier 如果当前事务具有相同名称的保存点,则删除旧保存点并设置新保存点。

ROLLBACK TO SAVEPOINT 语句将事务回滚到指定的保存点,而不终止事务。 保存点被设置后,当前事务对行所做的修改会撤消在回退,但 InnoDB 释放被保存点后存储在内存中的行锁。 (对于新插入的行,锁定信息由存储在行中的事务ID承载;锁定不单独存储在内存中。在这种情况下,行锁定在撤消时释放。)在a中设置的保存点比命名保存点更晚的时间被删除。

如果 ROLLBACK TO SAVEPOINT 语句返回以下错误,则表示不存在具有指定名称的保存点:

ERROR 1305(42000):SAVEPOINT identifier不存在

RELEASE SAVEPOINT 语句从当前事务的保存点集中删除指定的保存点。 不会发生提交或回滚。 如果保存点不存在则会出错。

如果执行a COMMIT 或未 ROLLBACK 命名保存点 则删除当前事务的所有保存 点。

调用存储的函数或激活触发器时,将创建新的保存点级别。 先前级别上的保存点变得不可用,因此不会与新级别上的保存点冲突。 当函数或触发器终止时,将释放它创建的任何保存点,并恢复先前的保存点级别。

13.3.5备份和解锁实例的锁定实例语法

锁定实例备份

解锁实例

LOCK INSTANCE FOR BACKUP 获取实例级 备份锁 ,该 在联机备份期间允许DML,同时防止可能导致快照不一致的操作。

执行该 LOCK INSTANCE FOR BACKUP 语句需要该 BACKUP_ADMIN 权限。 从早期版本执行就地升级到MySQL 8.0时, BACKUP_ADMIN 权限会自动授予具有该 RELOAD 权限的 用户

多个会话可以同时保存备份锁。

UNLOCK INSTANCE 释放当前会话持有的备份锁。 如果会话终止,则会释放会话持有的备份锁。

LOCK INSTANCE FOR BACKUP 防止创建,重命名或删除文件。 和帐户管理声明被阻止。 请参见 第13.7.1节“帐户管理语句” 修改 未在 重做日志中 记录的文件的 操作 也会被阻止。 REPAIR TABLE TRUNCATE TABLE OPTIMIZE TABLE InnoDB InnoDB

LOCK INSTANCE FOR BACKUP 允许仅影响用户创建的临时表的DDL操作。 实际上,在保留备份锁定时,可以创建,重命名或删除属于用户创建的临时表的文件。 还允许创建二进制日志文件。

获取的备份锁 LOCK INSTANCE FOR BACKUP 独立于事务锁和锁定 ,并允许以下语句序列: FLUSH TABLES tbl_name [, tbl_name] ... WITH READ LOCK

锁定实例备份;
FLUSH TABLES tbl_name[,tbl_name] ......阅读锁定;
解锁表;
解锁实例;
FLUSH TABLES tbl_name[,tbl_name] ......阅读锁定;
锁定实例备份;
解锁实例;
解锁表;

lock_wait_timeout 设置定义了 LOCK INSTANCE FOR BACKUP 语句在放弃之前等待获取锁定 的时间量

13.3.6 LOCK TABLES和UNLOCK TABLES语法

LOCK TABLES
     tbl_name[[AS] alias] lock_type
    [,tbl_name[[AS] alias] lock_type] ......

lock_type:{
    阅读[本地]
  | [LOW_PRIORITY]写
}

解锁表格

MySQL使客户端会话能够显式获取表锁,以便与其他会话协作以访问表,或者防止其他会话在会话需要对其进行独占访问期间修改表。 会话只能为自己获取或释放锁。 一个会话无法获取另一个会话的锁定或释放另一个会话持有的锁定。

锁可用于模拟事务或在更新表时获得更快的速度。 这在 表锁定限制和条件 中有更详细的解释

LOCK TABLES 显式获取当前客户端会话的表锁。 可以为基表或视图获取表锁。 您必须具有该 LOCK TABLES 特权,并且 SELECT 每个对象 特权都被锁定。

对于视图锁定, LOCK TABLES 视图中 使用的所有基表添加到要锁定的表集中并自动锁定它们。 如果 LOCK TABLES 使用 显式锁定 表,则触发器中使用的任何表也会被隐式锁定,如 LOCK TABLES和Triggers中所述

如果使用显式锁定表 LOCK TABLES ,则会打开并隐式锁定由外键约束关联的任何表。 对于外键检查, LOCK TABLES READ 对相关表 执行共享只读锁( )。 对于级联更新, LOCK TABLES WRITE 对操作中涉及的相关表 采用无共享写锁( )。

UNLOCK TABLES 显式释放当前会话持有的任何表锁。 LOCK TABLES 在获取新锁之前,隐式释放当前会话持有的任何表锁。

另一个用途 UNLOCK TABLES 是释放使用该 FLUSH TABLES WITH READ LOCK 语句 获取的全局读锁定 ,这使您可以锁定所有数据库中的所有表。 请参见 第13.7.7.3节“FLUSH语法” (如果您拥有可以及时拍摄快照的Veritas等文件系统,这是一种非常方便的备份方式。)

表锁仅保护其他会话不适当的读取或写入。 持有 WRITE 的会话 可以执行表级操作,例如 DROP TABLE TRUNCATE TABLE 对于会话持有 READ 锁, DROP TABLE 并且 TRUNCATE TABLE 操作是不允许的。

以下讨论仅适用于非 TEMPORARY 表。 LOCK TABLES 允许(但忽略) TEMPORARY 表。 该表可以通过创建它的会话自由访问,而不管其他锁定可能有效。 不需要锁定,因为没有其他会话可以看到该表。

表锁获取

要在当前会话中获取表锁,请使用 LOCK TABLES 获取元数据锁 语句(请参见 第8.11.4节“元数据锁定” )。

可以使用以下锁定类型:

READ [LOCAL] 锁:

  • 持有锁的会话可以读取表(但不能写入)。

  • 多个会话可以同时获取 READ 锁定。

  • 其他会话可以在不明确获取 READ 锁的 情况下读取表

  • LOCAL 修改使不冲突的 INSERT 其他会话语句(并发插入),而持有锁来执行。 (请参见 第8.11.3节“并发插入” 。)但是, READ LOCAL 如果要在保持锁定时使用服务器外部的进程操作数据库 则无法使用。 对于 InnoDB 表格, READ LOCAL 与之相同 READ

[LOW_PRIORITY] WRITE 锁:

  • 持有锁的会话可以读写表。

  • 只有持有锁的会话才能访问该表。 在释放锁之前,没有其他会话可以访问它。

  • 在锁定时,其他会话阻止对表的请求 WRITE

  • LOW_PRIORITY 修饰符无效。 在以前的MySQL版本中,它会影响锁定行为,但这不再适用。 它现已弃用,其使用会产生警告。 WRITE 无需 使用 LOW_PRIORITY

WRITE 锁通常具有比 READ 更高的优先级, 以确保尽快处理更新。 这意味着,如果一个会话获得 READ 锁定,然后另一个会话请求 WRITE 锁定,则后续 READ 锁定请求将一直等到请求 WRITE 锁定 的会话 获得锁定并将其释放。 (对于 max_write_lock_count 系统变量的 小值,可能会出现此策略的例外情况 ;请参见 第8.11.4节“元数据锁定” 。)

如果 LOCK TABLES 语句必须由于其他会话在任何表上持有的锁而等待,则它将一直阻塞,直到可以获取所有锁。

需要锁定的会话必须在单个 LOCK TABLES 语句中 获取所需的所有锁定 在保持如此获得的锁的同时,会话只能访问锁定的表。 例如,在以下语句序列中,尝试访问时发生错误, t2 因为它未在 LOCK TABLES 语句中 锁定

mysql> LOCK TABLES t1 READ;
mysql>SELECT COUNT(*) FROM t1;
+ ---------- +
| COUNT(*)|
+ ---------- +
| 3 |
+ ---------- +
MySQL的> SELECT COUNT(*) FROM t2;
ERROR 1100(HY000):表't2'未使用LOCK TABLES锁定

INFORMATION_SCHEMA 数据库中的 是一个例外。 即使会话持有获得的表锁,也可以在不显式锁定的情况下访问它们 LOCK TABLES

您不能使用相同的名称在单个查询中多次引用锁定的表。 请改用别名,并为表和每个别名获取单独的锁:

mysql> LOCK TABLE t WRITE, t AS t1 READ;
mysql>INSERT INTO t SELECT * FROM t;
ERROR 1100:表't'未使用LOCK TABLES锁定
MySQL的> INSERT INTO t SELECT * FROM t AS t1;

第一个错误发生, INSERT 因为对锁定表有两个相同名称的引用。 第二个 INSERT 成功,因为对表的引用使用不同的名称。

如果您的语句通过别名引用表,则必须使用相同的别名锁定表。 如果不指定别名,则无法锁定表:

mysql> LOCK TABLE t READ;
mysql>SELECT * FROM t AS myalias;
ERROR 1100:表'myalias'没有锁定LOCK TABLES

相反,如果使用别名锁定表,则必须使用该别名在语句中引用它:

mysql> LOCK TABLE t AS myalias READ;
mysql>SELECT * FROM t;
ERROR 1100:表't'未使用LOCK TABLES锁定
MySQL的> SELECT * FROM t AS myalias;
注意

LOCK TABLES 或者 UNLOCK TABLES ,当应用于分区表时,始终锁定或解锁整个表; 这些语句不支持分区锁定修剪。 请参阅 分区和锁定

表锁定释放

当释放会话持有的表锁时,它们都会同时释放。 会话可以显式释放其锁,或者可以在某些条件下隐式释放锁。

  • 会话可以显式释放其锁 UNLOCK TABLES

  • 如果会话 LOCK TABLES 在已经持有锁的情况下 发出 获取锁 语句,则在授予新锁之前将隐式释放其现有锁。

  • 如果会话开始事务(例如,with START TRANSACTION ), UNLOCK TABLES 则执行 隐式 操作,这会导致释放现有锁。 (有关表锁定和事务之间交互的其他信息,请参阅 表锁定和事务的交互 。)

如果客户端会话的连接终止,无论是正常还是异常,服务器都会隐式释放会话持有的所有表锁(事务性和非事务性)。 如果客户端重新连接,则锁将不再有效。 此外,如果客户端具有活动事务,则服务器在断开连接时回滚事务,如果发生重新连接,则新会话将以启用自动提交开始。 因此,客户可能希望禁用自动重新连接。 使用自动重新连接时,如果发生重新连接,则不会通知客户端,但任何表锁或当前事务都将丢失。 禁用自动重新连接后,如果连接断开,则发出的下一个语句将发生错误。 客户端可以检测错误并采取适当的操作,例如重新获取锁或重做事务。 看到 第28.7.28节“C API自动重新连接控制”

注意

如果您 ALTER TABLE 在锁定的表上 使用 它,它可能会被解锁。 例如,如果您尝试第二次 ALTER TABLE 操作,结果可能是错误 要处理此问题,请在第二次更改之前再次锁定表格。 另请参见 第B.4.6.1节“ALTER TABLE的问题” Table 'tbl_name' was not locked with LOCK TABLES

表锁定和事务的交互

LOCK TABLES UNLOCK TABLES 与交易的使用互动如下:

  • LOCK TABLES 不是事务安全的,并且在尝试锁定表之前隐式提交任何活动事务。

  • UNLOCK TABLES 隐式提交任何活动事务,但仅限 LOCK TABLES 于已用于获取表锁。 例如,在以下一组语句中, UNLOCK TABLES 释放全局读锁但不提交事务,因为没有表锁有效:

    带读锁的冲洗表;
    开始交易;
    选择 ... ;
    解锁表;
    
  • 开始事务(例如,with START TRANSACTION )隐式提交任何当前事务并释放现有表锁。

  • FLUSH TABLES WITH READ LOCK 获得全局读锁定,而不是表锁,所以它不会受到相同的行为 LOCK TABLES ,并 UNLOCK TABLES 相对于表锁定和隐式的提交。 例如, START TRANSACTION 不释放全局读锁定。 请参见 第13.7.7.3节“FLUSH语法”

  • 隐式导致事务提交的其他语句不会释放现有的表锁。 有关此类语句的列表,请参见 第13.3.3节“导致隐式提交的语句”

  • 使用 LOCK TABLES UNLOCK TABLES 使用事务表(如 InnoDB 表) 的正确方法是使用 SET autocommit = 0 (非 START TRANSACTION )后跟 开始事务 LOCK TABLES ,并且 UNLOCK TABLES 在显式提交事务之前 不调用 例如,如果您需要写入表 t1 并从表中读取 t2 ,则可以执行以下操作:

    SET autocommit = 0;
    LOCK TABLES t1 WRITE,t2 READ,...;
    ... do something with tables t1 and t2 here ...
    承诺;
    解锁表;
    

    当你调用时 LOCK TABLES InnoDB 内部采用自己的表锁,并且MySQL采用自己的表锁。 InnoDB 在下次提交时释放其内部表锁,但是要释放其表锁,MySQL必须调用 UNLOCK TABLES 你不应该 autocommit = 1 ,因为然后 InnoDB 在调用之后立即释放它的内部表锁 LOCK TABLES ,并且很容易发生死锁。 InnoDB 如果 autocommit = 1 ,为了帮助旧应用程序避免不必要的死锁, 根本不获取内部表锁

  • ROLLBACK 不释放表锁。

锁定表和触发器

如果 LOCK TABLES 使用 显式锁定 表,则触发器中使用的任何表也会被隐式锁定:

  • 锁定与使用 LOCK TABLES 语句 明确获取的锁定同时进行

  • 锁定在触发器中使用的表取决于该表是否仅用于读取。 如果是这样,读锁定就足够了。 否则,使用写锁定。

  • 如果显式锁定表以进行读取 LOCK TABLES ,但需要锁定以进行写入,因为它可能在触发器中被修改,则会执行写锁定而不是读取锁定。 (也就是说,由于表在触发器中的出现而需要隐式写锁定会导致表的显式读锁定请求转换为写锁定请求。)

假设您锁定了两个表, t1 t2 使用以下语句:

LOCK TABLES t1 WRITE,t2 READ;

如果 t1 t2 有任何触发器,触发器中使用的表也将被锁定。 假设 t1 有一个如下定义的触发器:

创建触发器t1_a_ins在每次插入t1之后插入
开始
  更新t4 SET count = count + 1
      WHERE id = NEW.id AND EXISTS(SELECT a FROM t3);
  插入t2值(1,2);
结束;

LOCK TABLES 语句 的结果 t1 并且 t2 因为它们出现在语句中 t3 t4 被锁定 ,并且 因为它们在触发器中使用 被锁定:

  • t1 根据 WRITE 锁定请求 被锁定以进行写入

  • t2 即使请求是锁定,也会被锁定以进行写入 READ 发生这种情况是因为 t2 插入到触发器中,因此 READ 请求将转换为 WRITE 请求。

  • t3 被锁定以进行读取,因为它只能从触发器中读取。

  • t4 被锁定以进行写入,因为它可能在触发器中更新。

表锁定限制和条件

您可以安全地用于 KILL 终止等待表锁定的会话。 请参见 第13.7.7.4节“KILL语法”

LOCK TABLES 并且 UNLOCK TABLES 不能在存储的程序中使用。

在表 performance_schema 的数据库不能被锁定 LOCK TABLES ,除了 表。 setup_xxx

而下面的语句是禁止的 LOCK TABLES :声明生效 CREATE TABLE CREATE TABLE ... LIKE CREATE VIEW DROP VIEW ,和存储函数和过程和事件DDL语句。

对于某些操作, mysql 必须访问数据库中的 系统表 例如,该 HELP 语句需要服务器端帮助表的内容,并且 CONVERT_TZ() 可能需要读取时区表。 服务器隐式锁定系统表以供必要时读取,以便您无需显式锁定它们。 这些表如上所述:

mysql.help_category
mysql.help_keyword
mysql.help_relation
mysql.help_topic
mysql.time_zone
mysql.time_zone_leap_second
mysql.time_zone_name
mysql.time_zone_transition
mysql.time_zone_transition_type

如果要 WRITE 使用 LOCK TABLES 语句 显式地 锁定任何这些表 ,则表必须是唯一锁定的表; 没有其他表可以使用相同的语句锁定。

通常,您不需要锁定表,因为所有单个 UPDATE 语句都是原子的; 没有其他会话可以干扰任何其他当前正在执行的SQL语句。 但是,在某些情况下,锁定表可能会提供一个优势:

  • 如果要在一组 MyISAM 上运行许多操作 ,则锁定要使用的表会快得多。 锁定 MyISAM 表加快了对它们的插入,更新或删除,因为MySQL在 UNLOCK TABLES 调用 之前不会刷新锁定表的密钥缓存 通常,在每个SQL语句之后刷新密钥缓存。

    锁定表的缺点是没有会话可以更新 READ 锁定表(包括持有锁的表),并且没有会话可以访问 WRITE 除了持有锁的表之外的锁定表。

  • 如果要将表用于非事务性存储引擎,则必须使用, LOCK TABLES 如果要确保没有其他会话修改a SELECT a之间的表 UPDATE 此处显示的示例需要 LOCK TABLES 安全执行:

    LOCK TABLES trans READ,客户写信;
    SELECT SUM(value)FROM trans WHERE customer_id =some_id ;
    更新客户
      SET total_value = sum_from_previous_statement
      WHERE customer_id =some_id ;
    解锁表;
    

    如果没有 LOCK TABLES ,则另一个会话可能会 trans 在执行 SELECT UPDATE 语句 之间 表中 插入一个新行

LOCK TABLES 在许多情况下, 您可以 通过使用相对更新( )或 函数 来避免使用 UPDATE customer SET value=value+new_value LAST_INSERT_ID()

您也可以通过避免使用用户级别咨询锁功能锁定在某些情况下,表 GET_LOCK() RELEASE_LOCK() 这些锁保存在服务器的哈希表中, pthread_mutex_lock() pthread_mutex_unlock() 以高速实现。 请参见 第12.14节“锁定功能”

有关 锁定策略的更多信息, 请参见 第8.11.1节“内部锁定方法”

13.3.7 SET TRANSACTION语法

SET [GLOBAL | SESSION] TRANSACTION
     transaction_characteristic[,transaction_characteristic] ......

transaction_characteristic:{
    隔离级别level
  |access_mode
}

level:{
     可重复阅读
   | 阅读提交
   | 阅读不满意
   | SERIALIZABLE
}

access_mode:{
     读写
   | 只读
}

此语句指定 事务 特征。 它采用逗号分隔的一个或多个特征值的列表。 每个特征值设置事务 隔离级别 或访问模式。 隔离级别用于 InnoDB 表上的 操作 访问模式指定事务是以读/写还是只读模式运行。

另外, SET TRANSACTION 可以包含一个可选的 GLOBAL SESSION 关键字来表示该语句的范围。

事务隔离级别

要设置事务隔离级别,请使用 子句。 不允许 在同一 语句中 指定多个 子句 ISOLATION LEVEL level ISOLATION LEVEL SET TRANSACTION

默认隔离级别为 REPEATABLE READ 其他允许值是 READ COMMITTED READ UNCOMMITTED SERIALIZABLE 有关这些隔离级别的信息,请参见 第15.7.2.1节“事务隔离级别”

交易访问模式

要设置事务访问模式,请使用 READ WRITE or READ ONLY 子句。 不允许在同一 SET TRANSACTION 语句中 指定多个access-mode子句

默认情况下,事务以读/写模式进行,读取和写入都允许在事务中使用的表。 可以使用 SET TRANSACTION 访问模式 明确指定此模式 READ WRITE

如果将事务访问模式设置为 READ ONLY ,则禁止对表进行更改。 这可以使存储引擎能够在不允许写入时实现性能改进。

在只读模式下,仍然可以 TEMPORARY 使用DML语句 更改使用 关键字 创建的 表。 与永久表一样,不允许使用DDL语句进行更改。

READ WRITE READ ONLY 接入方式也可以使用一个独立的事务中指定 START TRANSACTION 的语句。

交易特征范围

您可以在全局,当前会话或仅下一个事务中设置事务特征:

  • 使用 GLOBAL 关键字:

    • 该声明适用于所有后续会话。

    • 现有会话不受影响。

  • 使用 SESSION 关键字:

    • 该语句适用于当前会话中执行的所有后续事务。

    • 该等陈述在交易中是允许的,但不会影响当前正在进行的交易。

    • 如果在事务之间执行,则该语句将覆盖任何先前的语句,该语句设置命名特征的下一个事务值。

  • 没有任何 SESSION GLOBAL 关键字:

    • 该声明仅适用于会话中执行的下一个单个事务。

    • 后续事务将恢复为使用指定特征的会话值。

    • 交易中不允许使用该声明:

      MySQL的> START TRANSACTION;
      查询OK,0行受影响(0.02秒)
      
      MySQL的> SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
      ERROR 1568(25001):无法更改交易特征
      交易正在进行中
      

对全局事务特征的更改需要 CONNECTION_ADMIN SUPER 特权。 任何会话都可以自由更改其会话特征(即使在事务中间),也可以更改其下一个事务的特征(在该事务开始之前)。

要在服务器启动时设置全局隔离级别,请使用 命令行或选项文件中的选项。 此选项使用破折号,而不是空间,所以允许值是 ,或 --transaction-isolation=level level READ-UNCOMMITTED READ-COMMITTED REPEATABLE-READ SERIALIZABLE

同样,要在服务器启动时设置全局事务访问模式,请使用该 --transaction-read-only 选项。 默认值为 OFF (读/写模式),但可以将该值设置 ON 为只读模式。

例如,要将隔离级别设置为 REPEATABLE READ 和访问模式 READ WRITE ,请在 [mysqld] 选项文件 部分中 使用以下行

的[mysqld]
transaction-isolation = REPEATABLE-READ
transaction-read-only = OFF

在运行时,可以使用 SET TRANSACTION 语句 间接设置全局,会话和下一个事务范围级别的特征 ,如前所述。 它们也可以使用直接设置 SET 语句分配值 transaction_isolation transaction_read_only 系统变量:

下表显示了每个 SET TRANSACTION 和变量赋值语法 设置的特征范围级别

表13.9事务特征的SET TRANSACTION语法

句法 受影响的特征范围
SET GLOBAL TRANSACTION transaction_characteristic 全球
SET SESSION TRANSACTION transaction_characteristic 会议
SET TRANSACTION transaction_characteristic 仅限下一笔交易

表13.10事务特征的SET语法

句法 受影响的特征范围
SET GLOBAL var_name = value 全球
SET @@GLOBAL.var_name = value 全球
SET PERSIST var_name = value 全球
SET @@PERSIST.var_name = value 全球
SET PERSIST_ONLY var_name = value 没有运行时效果
SET @@PERSIST_ONLY.var_name = value 没有运行时效果
SET SESSION var_name = value 会议
SET @@SESSION.var_name = value 会议
SET var_name = value 会议
SET @@var_name = value 仅限下一笔交易

可以在运行时检查事务特征的全局值和会话值:

SELECT @@ GLOBAL.transaction_isolation,@@ GLOBAL.transaction_read_only;
SELECT @@ SESSION.transaction_isolation,@@ SESSION.transaction_read_only;

13.3.8 XA交易

存储引擎 可以 支持 XA 事务 InnoDB MySQL XA实现基于X / Open CAE文档 分布式事务处理:XA规范 本文件由The Open Group出版,可从 http://www.opengroup.org/public/pubs/catalog/c193.htm获取 第C.6节“XA事务限制” 中描述了当前XA实现的 限制

在客户端,没有特殊要求。 MySQL服务器的XA接口由以 XA 关键字 开头的SQL语句组成 MySQL客户端程序必须能够发送SQL语句并理解XA语句接口的语义。 它们不需要与最近的客户端库链接。 较旧的客户端库也可以工作。

在MySQL连接器中,MySQL Connector / J 5.0.0和更高版本通过一个为您处理XA SQL语句接口的类接口直接支持XA。

XA支持分布式事务,即允许多个单独的事务资源参与全局事务的能力。 事务资源通常是RDBMS,但可能是其他类型的资源。

全局事务涉及几个本身是事务性的操作,但所有操作必须作为一个组成功完成,或者全部作为一个组回滚。 从本质上讲,这会将ACID属性 扩展 到一个级别 ”, 这样多个ACID事务就可以作为具有ACID属性的全局操作的组件一起执行。 (与非分布式事务一样, SERIALIZABLE 如果您的应用程序对读取现象敏感 ,则 可能是首选。 REPEATABLE READ 可能不足以进行分布式事务。)

分布式事务的一些示例:

  • 应用程序可以充当将消息传递服务与RDBMS相结合的集成工具。 该应用程序确保处理涉及事务数据库的消息发送,检索和处理的事务都发生在全局事务中。 您可以将其视为 交易电子邮件”。

  • 应用程序执行涉及不同数据库服务器的操作,例如MySQL服务器和Oracle服务器(或多个MySQL服务器),其中涉及多个服务器的操作必须作为全局事务的一部分发生,而不是作为每个服务器本地的单独事务。

  • 银行将帐户信息保存在RDBMS中,并通过自动柜员机(ATM)分配和接收资金。 有必要确保ATM操作正确地反映在帐户中,但仅靠RDBMS无法做到这一点。 全球事务管理器集成了ATM和数据库资源,以确保金融交易的整体一致性。

使用全局事务的应用程序涉及一个或多个资源管理器和事务管理器:

  • 资源管理器(RM)提供对事务资源的访问。 数据库服务器是一种资源管理器。 必须可以提交或回滚RM管理的事务。

  • 事务管理器(TM)协调作为全局事务一部分的事务。 它与处理每个事务的RM进行通信。 全局事务中的各个事务是全局事务的 分支 全局事务及其分支由后面描述的命名方案标识。

XA的MySQL实现使MySQL服务器可以充当资源管理器,处理全局事务中的XA事务。 连接到MySQL服务器的客户端程序充当事务管理器。

要执行全局事务,必须知道涉及哪些组件,并将每个组件置于可以提交或回滚的位置。 根据每个组件报告的成功能力,它们必须全部提交或回滚为原子组。 也就是说,要么所有组件都必须提交,要么所有组件都必须回滚。 要管理全局事务,必须考虑任何组件或连接网络可能会失败。

执行全局事务的过程使用两阶段提交(2PC)。 这是在执行了全局事务的分支执行的操作之后发生的。

  1. 在第一阶段,所有分支都准备好了。 也就是说,TM告诉他们准备提交。 通常,这意味着管理分支的每个RM都会记录稳定存储中分支的操作​​。 分支表明他们是否能够这样做,并且这些结果用于第二阶段。

  2. 在第二阶段,TM告诉RM是否提交或回滚。 如果所有分支在准备好时表示他们能够提交,则告知所有分支都要提交。 如果任何分支在准备时指示它将无法提交,则告知所有分支都回滚。

在某些情况下,全局事务可能使用单阶段提交(1PC)。 例如,当事务管理器发现全局事务只包含一个事务资源(即单个分支)时,可以告诉该资源同时准备和提交。

13.3.8.1 XA事务SQL语法

要在MySQL中执行XA事务,请使用以下语句:

XA {START | BEGIN} xid[JOIN | RESUME]

XA END xid[SUSPEND [FOR MIGRATE]]

XA PREPARE xid

XA COMMIT xid[单相]

XA ROLLBACK xid

XA RECOVER [CONVERT XID]

因为 XA START 不支持 JOIN RESUME 子句。

因为 XA END SUSPEND [FOR MIGRATE] 条款不受支持。

每个XA语句都以 XA 关键字 开头,其中 大多数都需要一个 xid 值。 An xid 是XA事务标识符。 它指示该语句适用于哪个事务。 xid 值由客户端提供,或由MySQL服务器生成。 一个 xid 值有一到三个部分:

xidgtrid[,bqual[,formatID]]

gtrid 是一个全局事务标识符, bqual 是一个分支限定符, formatID 是一个标识 gtrid bqual 使用的格式的数字 如语法所示, bqual 并且 formatID 是可选的。 如果没有给出 默认 bqual '' formatID 如果没有给出 ,默认 值为1。

gtrid 并且 bqual 必须是字符串文字,每个字符长度最多为64个字节(不是字符)。 gtrid 并且 bqual 可以通过多种方式指定。 您可以使用带引号的字符串( 'ab' ),十六进制字符串( X'6162' 0x6162 )或位值( )。 b'nnnn'

formatID 是无符号整数。

gtrid bqual 值以字节为MySQL服务器的底层XA支持例程解释。 但是,在解析包含XA语句的SQL语句时,服务器将使用某些特定字符集。 为安全起见,写作 gtrid bqual 十六进制字符串。

xid 值通常由事务管理器生成。 一个TM生成的值必须与其他TM生成的值不同。 给定的TM必须能够 xid XA RECOVER 语句 返回的值列表中 识别自己的

XA START xid 使用给定 xid 启动XA事务 每个XA事务必须具有唯一 xid 值,因此该值当前不能由另一个XA事务使用。 使用 gtrid bqual 评估唯一性 必须使用与 语句 xid 中给出的值 相同的 来指定XA事务的所有后续XA XA START 语句。 如果您使用任何这些语句但指定的 xid 值与某些现有XA事务不对应,则会发生错误。

一个或多个XA事务可以是同一全局事务的一部分。 给定全局事务中的所有XA事务必须在 gtrid 值中 使用相同 xid 值。 因此, gtrid 值必须是全局唯一的,这样才不会对给定XA事务所属的全局事务产生歧义。 对于 全局事务中的每个XA事务 bqual xid 一部分 必须不同。 bqual 值不同 的要求 是当前MySQL XA实现的限制。它不是XA规范的一部分。)

XA RECOVER 语句返回MySQL服务器上处于该 PREPARED 状态的 那些XA事务的信息 (请参见 第13.3.8.2节“XA事务状态” 。)输出包括服务器上每个此类XA事务的行,而不管哪个客户端启动它。

XA RECOVER 需要 XA_RECOVER_ADMIN 特权。 此权限要求可防止用户发现除自己以外的未完成的准备XA事务的XID值。 它不会影响XA事务的正常提交或回滚,因为启动它的用户知道它的XID。

XA RECOVER 输出行如下所示(对于例如 xid 由部件的值 'abc' 'def' 7 ):

MySQL的> XA RECOVER;
+ ---------- + -------------- -------------- + -------- + +
| formatID | gtrid_length | bqual_length | 数据|
+ ---------- + -------------- -------------- + -------- + +
| 7 | 3 | 3 | abcdef |
+ ---------- + -------------- -------------- + -------- + +

输出列具有以下含义:

  • formatID formatID 交易 一部分 xid

  • gtrid_length 在的字节长度 gtrid 的部分 xid

  • bqual_length 在的字节长度 bqual 的部分 xid

  • data gtrid bqual 部分的连接 xid

XID值可能包含不可打印的字符。 XA RECOVER 允许一个可选 CONVERT XID 子句,以便客户端可以以十六进制的形式请求XID值。

13.3.8.2 XA交易国

XA事务通过以下状态进行:

  1. 使用 XA START 启动一个XA事务,并把它的 ACTIVE 状态。

  2. 对于 ACTIVE XA事务,发出 构成 事务的SQL语句,然后发出 XA END 语句。 XA END 将交易置于该 IDLE 州。

  3. 对于 IDLE XA事务,您可以发出 XA PREPARE 语句或 XA COMMIT ... ONE PHASE 语句:

    • XA PREPARE 将交易置于该 PREPARED 州。 此时的 XA RECOVER 语句将 xid 在其输出中 包含事务的 值,因为 XA RECOVER 列出了该 PREPARED 状态 中的所有XA事务

    • XA COMMIT ... ONE PHASE 准备并提交交易。 由于事务终止 xid XA RECOVER 因此 不会列出

  4. 对于 PREPARED XA事务,您可以发出 XA COMMIT 语句来提交和终止事务,或者 XA ROLLBACK 回滚并终止事务。

这是一个简单的XA事务,它将一行作为全局事务的一部分插入表中:

MySQL的> XA START 'xatest';
查询正常,0行受影响(0.00秒)

MySQL的> INSERT INTO mytable (i) VALUES(10);
查询正常,1行受影响(0.04秒)

MySQL的> XA END 'xatest';
查询正常,0行受影响(0.00秒)

MySQL的> XA PREPARE 'xatest';
查询正常,0行受影响(0.00秒)

MySQL的> XA COMMIT 'xatest';
查询正常,0行受影响(0.00秒)

在给定客户端连接的上下文中,XA事务和本地(非XA)事务是互斥的。 例如,如果 XA START 已发出以开始XA事务,则在提交或回滚XA事务之前,无法启动本地事务。 相反,如果已启动本地事务 START TRANSACTION ,则在提交或回滚事务之前,不能使用任何XA语句。

如果XA事务处于该 ACTIVE 状态,则不能发出任何导致隐式提交的语句。 这会违反XA合同,因为您无法回滚XA交易。 如果您尝试执行此类语句,您将收到以下错误:

错误1399(XAE07):XAER_RMFAIL:无法执行命令
当全局事务处于ACTIVE状态时

上述注释适用的 语句 第13.3.3节“导致隐式提交的语句” 中列出

13.4复制语句

可以使用本节中描述的语句通过SQL接口控制复制。 语句分为控制主服务器的组,控制从服务器的组和可应用于任何复制服务器的组。

13.4.1控制主服务器的SQL语句

本节讨论管理主复制服务器的语句。 第13.4.2节“用于控制从属服务器的SQL语句” 讨论了用于管理从属服务器的语句。

除了此处描述的语句之外,以下 SHOW 语句还用于复制中的主服务器。 有关这些语句的信息,请参见 第13.7.6节“SHOW语法”

13.4.1.1 PURGE BINARY LOGS语法

PURGE {BINARY | MASTER} LOGS {
    至 'log_name ''
  | 之前datetime_expr
}

二进制日志是一组文件,其中包含有关MySQL服务器进行的数据修改的信息。 该日志由一组二进制日志文件和一个索引文件组成(请参见 第5.4.4节“二进制日志” )。

PURGE BINARY LOGS 语句删除指定日志文件名或日期之前的日志索引文件中列出的所有二进制日志文件。 BINARY 并且 MASTER 是同义词。 删除的日志文件也将从索引文件中记录的列表中删除,以便给定的日志文件成为列表中的第一个。

PURGE BINARY LOGS 需要 BINLOG_ADMIN 特权。 如果未使用 --log-bin 启用二进制日志记录 选项 启动服务器,则此语句无效

例子:

PURGE BINARY登录'mysql-bin.010';
在'2019-04-02 22:46:26'之前的PURGE BINARY LOGS

BEFORE 变种的 datetime_expr 参数值应该为一个 DATETIME 值(一个值 'YYYY-MM-DD hh:mm:ss' 格式)。

当从属设备复制时,此语句可以安全运行。 你无需阻止它们。 如果您有一个当前正在读取您尝试删除的日志文件之一的活动从服务器,则此语句不会删除正在使用的日志文件或晚于该日志文件的任何日志文件,但会删除任何早期日志文件。 在这种情况下会发出警告消息。 但是,如果未连接从属设备并且您正在清除其尚未读取的其中一个日志文件,则从属设备将在重新连接后无法复制。

要安全地清除二进制日志文件,请执行以下过程:

  1. 在每个从属服务器上,用于 SHOW SLAVE STATUS 检查它正在读取的日志文件。

  2. 获取主服务器上的二进制日志文件列表 SHOW BINARY LOGS

  3. 确定所有从属中最早的日志文件。 这是目标文件。 如果所有从站都是最新的,则这是列表中的最后一个日志文件。

  4. 备份要删除的所有日志文件。 (此步骤是可选的,但始终是可取的。)

  5. 清除所有日志文件,但不包括目标文件。

PURGE BINARY LOGS TO PURGE BINARY LOGS BEFORE .index 通过其他方式(例如 在Linux上 使用 rm 从系统中删除 文件中列出的二进制日志文件时 两者都会失败并显示错误 (Bug#18199,Bug#18453)要处理此类错误,请 .index 手动 编辑 文件(简单文本文件)以确保它仅列出实际存在的二进制日志文件,然后再次运行 PURGE BINARY LOGS 失败 语句。

在服务器的二进制日志到期期限后,将自动删除二进制日志文件。 可以在启动时以及刷新二进制日志时删除文件。 默认的二进制日志有效期为30天。 您可以使用 binlog_expire_logs_seconds 系统变量 指定备用到期期限 如果使用复制,则应指定一个有效期,该有效期不低于从属服务器可能滞后于主服务器的最长时间。

13.4.1.2 RESET MASTER语法

RESET MASTER [TO binary_log_file_index_number]

RESET MASTER 使您能够删除任何二进制日志文件及其相关的二进制日志索引文件,将主服务器返回到启动二进制日志记录之前的状态。 RESET MASTER 需要 RELOAD 特权。

警告

请谨慎使用此语句,以确保不会丢失二进制日志文件数据。

RESET MASTER 没有可选 TO 子句的 情况下 发出 删除索引文件中列出的所有二进制日志文件,将二进制日志索引文件重置为空,并从中开始创建新的二进制日志文件 1 使用optional TO 子句从 1 重置后的 数字开始创建二进制日志文件索引 发布 RESET MASTER 还清除 gtid_purged 系统变量和 gtid_executed 系统变量的值; 也就是说,发出此语句会将每个值设置为空字符串( '' )。 此语句还清除 mysql.gtid_executed 表(请参阅 mysql.gtid_executed表 )。

使用 RESET MASTER with TO 子句指定要启动的二进制日志文件索引号,通过提供替换 FLUSH BINARY LOGS PURGE BINARY LOGS TO 语句 的单个语句来简化故障转移 检查您是否使用合理的索引号值。 如果输入的值不正确,可以通过发出 RESET MASTER 包含或不包含该 TO 子句的 另一个 语句 来纠正此问题 如果未更正超出范围的值,则无法重新启动服务器。

以下示例演示了 TO 子句用法:

RESET MASTER TO 1234;

显示二进制日志;
+ ------------------- + ----------- ----------- + +
| Log_name | File_size | 加密|
+ ------------------- + ----------- ----------- + +
| master-bin.001234 | 154 | 没有|
+ ------------------- + ----------- ----------- + +
重要

RESET MASTER 没有该 TO 条款 的影响 与以下 PURGE BINARY LOGS 两个关键方式的影响不同:

  1. RESET MASTER 删除 索引文件中列出的 所有 二进制日志文件,只留下一个带有数字后缀的空二进制日志文件 .000001 ,而编号不会被重置 PURGE BINARY LOGS

  2. RESET MASTER 不是 打算,而任何复制的奴隶正在运行使用。 RESET MASTER 从属服务器运行时使用 的行为 是未定义的(因此不受支持),而 PURGE BINARY LOGS 在复制从服务器运行时可以安全使用。

另请参见 第13.4.1.1节“PURGE BINARY LOGS语法”

RESET MASTER TO 第一次设置主服务器和从服务器时, 没有该 子句可以证明是有用的,这样您就可以按如下方式验证设置:

  1. 启动主服务器和从服务器,然后开始复制(请参见 第17.1.2节“设置基于二进制日志文件位置的复制” )。

  2. 在主服务器上执行一些测试查询。

  3. 检查查询是否已复制到从属服务器。

  4. 当复制运行正常,问题 STOP SLAVE 后面 RESET SLAVE 的奴隶,然后验证从测试查询没有多余的数据在从服务器上存在。

  5. RESET MASTER 在master上 发出问题 以清理测试查询。

验证设置,重置主设备和从设备并确保测试生成的不需要的数据或二进制日志文件保留在主设备或从设备上后,您可以启动从设备并开始复制。

13.4.1.3 SET sql_log_bin语法

SET sql_log_bin = {OFF | ON}

sql_log_bin 变量控制是否为当前会话启用了对二进制日志的记录(假设已启用二进制日志本身)。 默认值为 ON 要禁用或启用当前会话的二进制日志记录,请将会话 sql_log_bin 变量 设置 OFF ON

将此变量设置 OFF 为会话以临时禁用二进制日志记录,同时更改不希望复制到从属服务器的主服务器。

设置此系统变量的会话值是受限制的操作。 会话用户必须具有足以设置受限会话变量的权限。 请参见 第5.1.9.1节“系统变量权限”

无法 sql_log_bin 在事务或子查询中 设置会话值

设置此变量 OFF 可防止将GTID分配给二进制日志中的事务 如果您使用GTID进行复制,这意味着即使稍后再次启用二进制日志记录,从此处写入日志的GTID也不会考虑同时发生的任何事务,因此实际上这些事务将丢失。

13.4.2用于控制从属服务器的SQL语句

本节讨论管理从属复制服务器的语句。 第13.4.1节“用于控制主服务器的SQL语句” 讨论了用于管理主服务器的语句。

除了此处描述的语句, SHOW SLAVE STATUS 并且 SHOW RELAYLOG EVENTS 还使用复制的奴隶。 有关这些语句的信息,请参见 第13.7.6.34节“显示从动状态语法” 第13.7.6.32节“显示RELAYLOG事件语法”

13.4.2.1更改主语法

改变主要option[,option] ...... [ channel_option]

option
    MASTER_BIND ='interface_name '
  | MASTER_HOST ='host_name '
  | MASTER_USER ='user_name '
  | MASTER_PASSWORD ='password '
  | MASTER_PORT = port_num
  | MASTER_CONNECT_RETRY = interval
  | MASTER_RETRY_COUNT = count
  | MASTER_DELAY = interval
  | MASTER_HEARTBEAT_PERIOD = interval
  | MASTER_LOG_FILE =' master_log_name'
  | MASTER_LOG_POS =master_log_pos
  | MASTER_AUTO_POSITION = {0 | 1}
  | RELAY_LOG_FILE =' relay_log_name'
  | RELAY_LOG_POS =relay_log_pos
  | MASTER_SSL = {0 | 1}
  | MASTER_SSL_CA =' ca_file_name'
  | MASTER_SSL_CAPATH =' ca_directory_name'
  | MASTER_SSL_CERT =' cert_file_name'
  | MASTER_SSL_CRL =' crl_file_name'
  | MASTER_SSL_CRLPATH =' crl_directory_name'
  | MASTER_SSL_KEY =' key_file_name'
  | MASTER_SSL_CIPHER =' cipher_list'
  | MASTER_SSL_VERIFY_SERVER_CERT = {0 | 1}
  | MASTER_TLS_VERSION =' protocol_list'
  | MASTER_PUBLIC_KEY_PATH =' key_file_name'
  | GET_MASTER_PUBLIC_KEY = {0 | 1}
  | IGNORE_SERVER_IDS =(server_id_list

channel_option
    FOR CHANNEL channel

server_id_list
    [ server_id[,server_id] ......]

CHANGE MASTER TO 更改从服务器用于连接主服务器的参数,读取主二进制日志和读取从中继日志。 它还会更新主信息和中继日志信息存储库的内容(请参见 第17.2.4节“复制中继和状态日志” )。 CHANGE MASTER TO 需要 REPLICATION_SLAVE_ADMIN SUPER 特权。

您可以 CHANGE MASTER TO 在没有先停止它的情况下在正在运行的从站上 发出 语句,具体取决于从属SQL线程和从属I / O线程的状态。 有关此类使用的规则将在本节后面提供。

当使用多线程从站(换句话说 slave_parallel_workers 大于0)时,停止从站可能会导致 从中继日志执行的事务序列中出现 间隙 ,无论从站是故意停用还是其他方式。 当存在这种差距时,发布 CHANGE MASTER TO 失败。 在这种情况下的解决方案是 START SLAVE UNTIL SQL_AFTER_MTS_GAPS 确保间隙被关闭的问题。

使用optional 子句可以命名该语句适用的复制通道。 提供 子句将 语句 应用于 特定复制通道,并用于添加新通道或修改现有通道。 例如,要添加名为channel2的新频道: FOR CHANNEL channel FOR CHANNEL channel CHANGE MASTER TO

CHANGE MASTER TO MASTER_HOST = host1,MASTER_PORT = 3002 FOR CHANNEL'channel2'

如果未命名子句且不存在额外通道,则该语句将应用于默认通道。

使用多个复制通道时,如果 CHANGE MASTER TO 语句未使用 子句 命名通道 ,则会发生错误。 有关 更多信息 请参见 第17.2.3节“复制通道” FOR CHANNEL channel

未指定的选项保留其值,除非在以下讨论中指出。 因此,在大多数情况下,不需要指定不更改的选项。

MASTER_HOST MASTER_USER MASTER_PASSWORD ,和 MASTER_PORT 到有关如何连接到其主从提供信息:

  • MASTER_HOST 并且 MASTER_PORT 是主主机及其TCP / IP端口的主机名(或IP地址)。

    注意

    复制不能使用Unix套接字文件。 您必须能够使用TCP / IP连接到主MySQL服务器。

    如果指定 MASTER_HOST MASTER_PORT 选项,则从属服务器假定主服务器与以前不同(即使选项值与其当前值相同。)在这种情况下,主二进制日志文件名和位置的旧值为考虑不再适用,因此,如果不指定 MASTER_LOG_FILE ,并 MASTER_LOG_POS 在声明中, MASTER_LOG_FILE='' MASTER_LOG_POS=4 以静默追加到它。

    设置 MASTER_HOST='' (即,明确其值设置为空字符串)是 一样的没有设置 MASTER_HOST 在所有。 尝试设置 MASTER_HOST 为空字符串失败并显示错误。

    检查用于换行( )字符的 MASTER_HOST 和其他 CHANGE MASTER TO 选项 ; 这些值中存在此类字符会导致语句失败 (Bug#11758581,Bug#50801) \n 0x0A ER_MASTER_INFO

  • MASTER_USER 并且 MASTER_PASSWORD 是用于连接到主服务器的帐户的用户名和密码。

    MASTER_USER 不能空虚; 设置 MASTER_USER = '' 值时 设置 或保持不设置 MASTER_PASSWORD 会导致错误(Bug#13427949)。

    CHANGE MASTER TO 语句中 用于MySQL Replication从属帐户的密码 长度限制为32个字符; 尝试使用超过32个字符的密码会导致 CHANGE MASTER TO 失败。

    运行 CHANGE MASTER TO 语句 的文本( 包括 MASTER_USER 和的 值) MASTER_PASSWORD 可以在并发 SHOW PROCESSLIST 语句 的输出中看到 START SLAVE 声明 的完整文本 也可见 SHOW PROCESSLIST 。)

选项与 选项指定的奴隶如何使用加密和密码,以确保复制连接。 即使在没有SSL支持的情况下编译的从站也可以更改这些选项。 它们将保存到主信息存储库,但如果从服务器未启用SSL支持,则会被忽略。 选项执行相同的功能, 并且 在描述客户端选项 第6.3.2节“的加密连接命令选项” 两套方案之间的对应关系,以及使用的 MASTER_SSL_xxx MASTER_TLS_VERSION MASTER_SSL_xxx MASTER_TLS_VERSION --ssl-xxx --tls-version MASTER_SSL_xxx MASTER_TLS_VERSION 选项来建立安全连接的解释如下 第17.3.9节“设置复制以使用加密连接”中

重要

要使用使用 caching_sha2_password 插件进行 身份验证的用户帐户连接到复制主 服务器,必须按 第17.3.9节“设置复制以使用加密连接”中 所述设置安全连接 ,或启用未加密连接以支持密码使用RSA密钥对进行交换。 caching_sha2_password 认证插件是从MySQL 8.0中创建新用户的默认(详见 第6.4.1.3,“缓存SHA-2插入式验证” )。 如果您创建或用于复制的用户帐户(由 MASTER_USER 选项)使用此身份验证插件,并且您没有使用安全连接,必须启用基于RSA密钥对的密码交换才能成功连接。

要启用基于RSA密钥对的密码交换,请指定 MASTER_PUBLIC_KEY_PATH GET_MASTER_PUBLIC_KEY=1 选项。 这些选项中的任何一个都为从站提供RSA公钥:

  • MASTER_PUBLIC_KEY_PATH 表示包含主服务器所需公钥的从属端副本的文件的路径名,用于基于RSA密钥对的密码交换。 该文件必须采用PEM格式。 此选项适用于使用 sha256_password caching_sha2_password 身份验证插件进行 身份验证的从属 服务器。 (对于 sha256_password MASTER_PUBLIC_KEY_PATH 只有在使用OpenSSL构建MySQL时才能使用。)

  • GET_MASTER_PUBLIC_KEY 指示是否从主设备请求基于RSA密钥对的密码交换所需的公钥。 此选项适用于使用 caching_sha2_password 身份验证插件 进行 身份验证的 从属 服务器。 对于使用此插件进行身份验证的帐户的连接,除非有请求,否则主服务器不会发送公钥,因此必须在客户端中请求或指定。 如果 MASTER_PUBLIC_KEY_PATH 给定并指定了有效的公钥文件,则优先于 GET_MASTER_PUBLIC_KEY

MASTER_HEARTBEAT_PERIOD MASTER_CONNECT_RETRY MASTER_RETRY_COUNT 选项控制从如何认识到主机的连接已经丢失,使尝试重新连接。

  • 所述 slave_net_timeout 系统变量指定的所述从等待任一多个数据或来自主设备的心跳信号,前从动认为连接断裂,中止读操作,并尝试重新连接的秒数。 默认值为60秒(一分钟)。

  • 如果连接仍然良好,则在没有数据的情况下停止连接超时的心跳间隔由该 MASTER_HEARTBEAT_PERIOD 选项 控制 在该秒数之后,心跳信号被发送到从设备,并且每当用事件更新主设备的二进制日志时,等待时间段被重置。 因此,只有在二进制日志文件中没有未发送的事件超过此时间段时,主服务器才会发送心跳。 心跳间隔 interval 是十进制值,范围为0到4294967秒,分辨率以毫秒为单位; 最小非零值为0.001。 设置 interval 为0完全禁用心跳。 心跳间隔默认为 slave_net_timeout 系统变量 值的一半 它记录在主信息日志中,并显示在 replication_connection_configuration 性能模式表中。 发出 RESET SLAVE 将心跳间隔重置为默认值。

    请注意,更改值或默认设置 slave_net_timeout 不会自动更改心跳间隔,无论是已明确设置还是使用先前计算的默认值。 如果设置 @@GLOBAL.slave_net_timeout 的值小于当前心跳间隔的值, 则会发出警告 如果 slave_net_timeout 更改,您还必须发出 CHANGE MASTER TO 将心跳间隔调整为适当的值,以便在连接超时之前发生心跳信号。 如果不这样做,心跳信号就没有效果,如果没有从主设备收到数据,则从设备可以重复重新连接尝试,从而创建僵尸转储线程。

  • 如果从站确实需要重新连接,则在超时后立即进行第一次重试。 MASTER_CONNECT_RETRY 指定重新连接尝试之间的间隔,并 MASTER_RETRY_COUNT 限制重新连接尝试的次数。 如果同时使用两个默认设置 MASTER_CONNECT_RETRY=60 ,则从站在 重新连接尝试之间等待60秒( ),并继续尝试以此速率重新连接60天( MASTER_RETRY_COUNT=86400 )。 这些值记录在主信息日志中,并显示在“ replication_connection_configuration 性能架构”表中。 MASTER_RETRY_COUNT 取代 --master-retry-count 服务器启动选项。

MASTER_DELAY 指定从站必须滞后的主站后面多少秒。 从主站接收的事件 interval 要比 在主站上执行的事件至少 晚几秒才执行。 默认值为0.如果 interval 不是0到2 31 -1 范围内的非负整数, 则会发生错误 有关更多信息,请参见 第17.3.12节“延迟复制”

当从属SQL线程停止时,可以在正在运行的从属服务器上执行 CHANGE MASTER TO 使用该 MASTER_DELAY 选项 语句

MASTER_BIND 用于具有多个网络接口的复制从站,并确定选择哪个从属网络接口连接到主站。

使用此选项配置的地址(如果有)可以 Master_Bind 在输出 列中 看到 SHOW SLAVE STATUS 在主信息存储库表中 mysql.slave_master_info ,该值可以看作 Master_bind 列。

NDB Cluster还支持将复制从站绑定到特定网络接口的能力。

MASTER_LOG_FILE 并且 MASTER_LOG_POS 是下一次线程启动时从属I / O线程应从主站开始读取的坐标。 RELAY_LOG_FILE 并且 RELAY_LOG_POS 是下一次线程启动时从属SQL线程应该从中继日志开始读取的坐标。 如果指定的 MASTER_LOG_FILE MASTER_LOG_POS ,你不能指定 RELAY_LOG_FILE RELAY_LOG_POS 如果您指定的任一 MASTER_LOG_FILE 或者 MASTER_LOG_POS ,你也可以不指定 MASTER_AUTO_POSITION = 1 (在本节后面介绍)。 如果没有的 MASTER_LOG_FILE MASTER_LOG_POS 指定,从使用的最后一个坐标 从SQL线程 CHANGE MASTER TO 发出。 这确保了复制中没有不连续性,即使从属SQL线程与从属I / O线程相比较迟,当您只想更改要使用的密码时也是如此。

一个 CHANGE MASTER TO 声明用人 RELAY_LOG_FILE RELAY_LOG_POS 或这两个选项可以在运行时从从SQL线程停止执行。 如果从属SQL线程和从属I / O线程中至少有一个正在运行,则保留中继日志; 如果两个线程都停止,则删除所有中继日志文件,除非至少 指定了 一个 RELAY_LOG_FILE RELAY_LOG_POS

RELAY_LOG_FILE 可以使用绝对路径或相对路径,并使用相同的基本名称 MASTER_LOG_FILE

MASTER_AUTO_POSITION = 1 与使用 CHANGE MASTER TO 中,从试图连接到使用基于GTID复制协议的主站。 CHANGE MASTER TO 仅当从属SQL和从属I / O线程都已停止时, 才能使用此选项 无论是从设备和主必须GTIDs启用( GTID_MODE=ON ON_PERMISSIVE, 或者 OFF_PERMISSIVE 在从服务器上,并 GTID_MODE=ON 在主站)。 自动定位被用于连接,因此由下式表示的坐标 MASTER_LOG_FILE MASTER_LOG_POS 没有被使用,以及使用这些选项之一或两者一起 MASTER_AUTO_POSITION = 1 导致错误。 如果从站上启用了多源复制,则需要设置 MASTER_AUTO_POSITION = 1 每个适用的复制通道的选项。

使用 MASTER_AUTO_POSITION = 1 set,在初始连接握手中,从站发送一个GTID集,其中包含已经收到,已提交或两者都已完成的事务。 主设备通过发送其二进制日志中记录的所有事务来响应,其GTID不包括在从设备发送的GTID集中。 此交换确保主服务器仅使用GTID发送从属尚未记录或已提交的事务。 如果从属设备从多个主设备接收事务,如菱形拓扑结构,则自动跳过功能可确保事务不会应用两次。 有关如何计算从站发送的GTID集的详细信息,请参见 第17.1.3.3节“GTID自动定位”

如果主服务器应发送的任何事务已从主服务器的二进制日志中清除,或 gtid_purged 通过其他方法 添加到 系统变量中 的GTID集中 ,则主服务器将错误 ER_MASTER_HAS_PURGED_REQUIRED_GTIDS 发送 给从服务器,并且复制不会开始。 将识别丢失的清除事务的GTID,并在警告消息 ER_FOUND_MISSING_GTIDS 中的主控错误日志中 列出 另外,如果在事务交换期间发现从属设备已经在GTID中记录或提交了主设备UUID的事务,但是主设备本身没有提交它们,主设备发送错误 ER_SLAVE_HAS_MORE_GTIDS_THAN_MASTER 到从站并且复制无法启动。 有关如何处理这些情况的信息,请参见 第17.1.3.3节“GTID自动定位”

通过检查性能架构 replication_connection_status 表或输出, 可以查看复制是否在启用自动定位的情况下运行 SHOW SLAVE STATUS 禁用 MASTER_AUTO_POSITION 再次选项使从恢复到基于文件的复制,在这种情况下,你还必须指定的一个或两个 MASTER_LOG_FILE MASTER_LOG_POS 选项。

IGNORE_SERVER_IDS 采用以逗号分隔的0个或更多服务器ID列表。 源于相应服务器的事件将被忽略,但日志轮换和删除事件除外,这些事件仍记录在中继日志中。

在循环复制中,始发服务器通常充当其自身事件的终结符,因此它们不会被应用多次。 因此,当删除圆中的一个服务器时,此选项在循环复制中很有用。 假设您有4个服务器的循环复制设置,服务器ID为1,2,3和4,服务器3失败。 通过启动从服务器2到服务器4的复制来弥补差距,您可以 在服务器4上发出 IGNORE_SERVER_IDS = (3) CHANGE MASTER TO 语句中 包含 它,告诉它使用服务器2作为主服务器而不是服务器3.这样做会导致它忽略而不是传播源自不再使用的服务器的任何语句。

如果 IGNORE_SERVER_IDS 包含服务器自己的ID,并且 --replicate-same-server-id 启用 选项启动 服务器 ,则会出现错误。

注意

当全局事务标识符(GTID)用于复制时,已自动忽略已应用的事务,因此该 IGNORE_SERVER_IDS 函数不是必需的,不推荐使用。 如果 gtid_mode=ON 为服务器设置了,则如果 IGNORE_SERVER_IDS CHANGE MASTER TO 语句中 包含该 选项, 则会发出弃用警告

主信息存储库和输出 SHOW SLAVE STATUS 提供当前被忽略的服务器列表。 有关更多信息,请参见 第17.2.4.2节“从站状态日志” 第13.7.6.34节“显示从站状态语法”

如果在 CHANGE MASTER TO 没有任何 IGNORE_SERVER_IDS 选项的 情况下发出语句 ,则会保留任何现有列表。 要清除被忽略的服务器列表,必须使用带有空列表的选项:

将主设备更改为IGNORE_SERVER_IDS =();

RESET SLAVE ALL 清除 IGNORE_SERVER_IDS

注意

如果 SET GTID_MODE=ON 在任何通道设置了现有服务器ID时 发出, 则会发出 弃用警告 IGNORE_SERVER_IDS 在启动基于GTID的复制之前,请检查并清除所涉及的服务器上所有被忽略的服务器ID列表。 SHOW_SLAVE_STATUS 语句显示被忽略的ID列表(如果有)。 如果确实收到了弃用警告,则可以 gtid_mode=ON 通过发出 CHANGE MASTER TO 包含 IGNORE_SERVER_IDS 带有空列表 选项 语句 来设置 列表。

调用 CHANGE MASTER TO 导致原先的值 MASTER_HOST MASTER_PORT MASTER_LOG_FILE ,并 MASTER_LOG_POS 要写入错误日志,以及有关从执行前的状态等信息。

CHANGE MASTER TO 导致正在进行的事务的隐式提交。 请参见 第13.3.3节“导致隐式提交的语句”

从MySQL 5.7开始, 删除了 STOP SLAVE 在发布任何 CHANGE MASTER TO 语句 之前 (以及 START SLAVE 之后) 执行的严格要求 而不是依赖于从属是否停止,行为 CHANGE MASTER TO 取决于从属SQL线程和从属I / O线程的状态; 现在停止或运行这些线程中的哪一个确定了 CHANGE MASTER TO 在给定时间点 可以或不能与 语句 一起使用的选项 此处列出了进行此确定的规则:

  • 如果SQL线程停止时,可以执行 CHANGE MASTER TO 使用被允许的其他方式的任意组合 RELAY_LOG_FILE RELAY_LOG_POS MASTER_DELAY 选择,即使从I / O线程运行。 当I / O线程运行时,此语句不能使用其他选项。

  • 如果I / O线程停止时,可以执行 CHANGE MASTER TO 使用任何选项,此语句(任何允许的组合) 除外 RELAY_LOG_FILE RELAY_LOG_POS MASTER_DELAY ,或 MASTER_AUTO_POSITION = 1 SQL线程运行时也是如此。

  • 在发出使用的 CHANGE MASTER TO 语句 之前,必须停止SQL线程和I / O线程 MASTER_AUTO_POSITION = 1

您可以使用检查从属SQL和I / O线程的当前状态 SHOW SLAVE STATUS

有关更多信息,请参见 第17.3.8节“在故障转移期间切换主站”

如果使用基于语句的复制和临时表,则 CHANGE MASTER TO 语句后面的 STOP SLAVE 语句可能会在从属服务器上留下临时表。 ER_WARN_OPEN_TEMP_TABLES_MUST_BE_ZERO 只要发生这种情况,就会发出 警告( )。 在这种情况下,您可以通过 Slave_open_temp_tables 在执行此类 CHANGE MASTER TO 语句 之前 确保 系统状态变量的值等于0 来避免这种情况

CHANGE MASTER TO 当您拥有主服务器的快照并且已记录与快照时间对应的主二进制日志坐标时,可用于设置从服务器。 将快照加载到从站以使其与主站同步后,您可以 在从站上 运行 以指定从站应开始读取主二进制日志的坐标。 CHANGE MASTER TO MASTER_LOG_FILE='log_name', MASTER_LOG_POS=log_pos

以下示例更改从站使用的主服务器,并建立从站开始读取的主二进制日志坐标。 当您要设置从属设备以复制主设备时,可以使用此选项:

改变主人
  MASTER_HOST = 'master2.example.com',
  MASTER_USER = '复制',
  MASTER_PASSWORD =' password',
  MASTER_PORT = 3306,
  MASTER_LOG_FILE = 'master2-bin.001',
  MASTER_LOG_POS = 4,
  MASTER_CONNECT_RETRY = 10;

下一个示例显示了较少使用的操作。 当从站具有您希望由于某种原因再次执行的中继日志文件时使用它。 为此,无需访问主服务器。 您只需要使用 CHANGE MASTER TO 并启动SQL thread( START SLAVE SQL_THREAD ):

改变主人
  RELAY_LOG_FILE =“从属中继bin.006”,
  RELAY_LOG_POS = 4025;

下表显示了字符串值选项的最大允许长度。

选项 最大长度
MASTER_HOST 255(MySQL 8.0.17之前的60)
MASTER_USER 96
MASTER_PASSWORD 32
MASTER_LOG_FILE 511
RELAY_LOG_FILE 511
MASTER_SSL_CA 511
MASTER_SSL_CAPATH 511
MASTER_SSL_CERT 511
MASTER_SSL_CRL 511
MASTER_SSL_CRLPATH 511
MASTER_SSL_KEY 511
MASTER_SSL_CIPHER 511
MASTER_TLS_VERSION 511
MASTER_PUBLIC_KEY_PATH 511

13.4.2.2更改复制过滤器语法

更改复制过滤器filter[,filter]
	[,...] [FOR CHANNEL channel]

filter
    REPLICATE_DO_DB =(db_list
  | REPLICATE_IGNORE_DB =(db_list
  | REPLICATE_DO_TABLE =(tbl_list
  | REPLICATE_IGNORE_TABLE =(tbl_list
  | REPLICATE_WILD_DO_TABLE =(wild_tbl_list
  | REPLICATE_WILD_IGNORE_TABLE =(wild_tbl_list
  | REPLICATE_REWRITE_DB =(db_pair_list

db_listdb_name[,db_name] [,...]

tbl_listdb_name.table_name[,db_name.table_name] [,...]
 wild_tbl_list
    ' db_pattern.table_pattern'[,' db_pattern.table_pattern'] [,...]

db_pair_listdb_pair)[,(db_pair)] [,...]

db_pairfrom_dbto_db

CHANGE REPLICATION FILTER 在slave上设置一个或多个复制过滤规则的方式与启动 带有复制过滤选项(如 或) 的slave mysqld 相同 与服务器选项的情况不同,此语句不需要重新启动服务器才能生效,只需要 首先 使用从属SQL线程停止 (并在 之后 重新启动 )。 需要 特权。 使用该 子句可以创建特定于复制通道的复制过滤器,例如,在多源复制从站上。 过滤器应用时没有特定的 --replicate-do-db --replicate-wild-ignore-table STOP SLAVE SQL_THREAD START SLAVE SQL_THREAD CHANGE REPLICATION FILTER REPLICATION_SLAVE_ADMIN SUPER FOR CHANNEL channel FOR CHANNEL 子句被视为全局过滤器,这意味着它们适用于所有复制通道。

注意

无法在为组复制配置的MySQL服务器实例上设置全局复制筛选器,因为在某些服务器上筛选事务会使该组无法就一致状态达成协议。 可以在不直接与组复制相关的复制通道上设置通道特定的复制筛选器,例如,组成员还充当组外部主服务器的复制从属服务器。 他们不能对设置 group_replication_applier group_replication_recovery 通道。

以下列表显示了 CHANGE REPLICATION FILTER 选项以及它们与 --replicate-* 服务器选项的关系:

REPLICATE_DO_DB REPLICATE_IGNORE_DB 过滤器 的精确效果 取决于基于语句的复制还是基于行的复制。 有关 更多信息 请参见 第17.2.5节“服务器如何评估复制过滤规则”

CHANGE REPLICATION FILTER 通过用逗号分隔 规则,可以在单个 语句中 创建多个复制过滤规则 ,如下所示:

更换复制过滤器
    REPLICATE_DO_DB =(d1),REPLICATE_IGNORE_DB =(d2);

发出刚刚显示的语句相当于 使用选项 启动slave mysqld --replicate-do-db=d1 --replicate-ignore-db=d2

在多源复制从属(使用多个复制通道处理来自不同源的事务)上,使用该 子句在复制通道上设置复制过滤器: FOR CHANNEL channel

CHANGE REPLICATION FILTER REPLICATE_DO_DB =(d1)FOR CHANNEL channel_1;

这使您可以创建特定于通道的复制筛选器,以筛选出源中的选定数据。 FOR CHANNEL 设置子句,复制过滤器声明作用于该从属复制通道去除具有相同滤波器类型与指定的复制过滤器的任何现有的复制过滤器,并使用指定的过滤器替换它们。 未修改语句中未明确列出的过滤器类型。 如果针对未配置的从属复制通道发出,则该语句将失败并显示 ER_SLAVE_CONFIGURATION 错误。 如果针对组复制通道发出,则该语句将失败并显示 ER_SLAVE_CHANNEL_OPERATION_NOT_ALLOWED 错误。

在配置了多个复制通道的复制从站上, CHANGE REPLICATION FILTER 使用no FOR CHANNEL 子句 发出会 为每个已配置的从复制通道和全局复制筛选器配置复制筛选器。 对于每种过滤器类型,如果语句中列出了过滤器类型,则该类型的任何现有过滤器规则将替换为最近发出的语句中指定的过滤器规则,否则将保留过滤器类型的旧值。 有关更多信息,请参见 第17.2.5.4节“基于复制通道的过滤器”

如果多次指定相同的过滤规则, 则实际 仅使用 最后一个 此类规则。 例如,此处显示的两个语句具有完全相同的效果,因为 REPLICATE_DO_DB 忽略了第一个语句中的第 一个 规则:

更换复制过滤器
    REPLICATE_DO_DB =(db1,db2),REPLICATE_DO_DB =(db3,db4);

更换复制过滤器
    REPLICATE_DO_DB =(db3,db4);
警告

此行为与 --replicate-* 筛选选项的 行为不同, 其中多次指定相同选项会导致创建多个筛选规则。

不需要引用不包含任何特殊字符的表和数据库的名称。 REPLICATION_WILD_TABLE REPLICATION_WILD_IGNORE_TABLE 一起 使用的值 是字符串表达式,可能包含(特殊)通配符,因此必须引用。 这在以下示例语句中显示:

更换复制过滤器
    REPLICATE_WILD_DO_TABLE =('db1.old%');

更换复制过滤器
    REPLICATE_WILD_IGNORE_TABLE =('db1.new%','db2.new%');

用于 REPLICATE_REWRITE_DB 表示 数据库名称 ; 每个这样的值必须括在括号中。 以下语句 db1 将master 上数据库 发生的语句重写 db2 为slave上的 数据库

CHANGE REPLICATION FILTER REPLICATE_REWRITE_DB =((db1,db2));

刚才显示的语句包含两组括号,一组包含数据库名称,另一组包含整个列表。 这也许是更容易看到在下面的例子中,它创建了两个 rewrite-db 规则,一个重写的数据库 dbA dbB ,和一个重写数据库 dbC dbD

更换复制过滤器
  REPLICATE_REWRITE_DB =((dbA,dbB),(dbC,dbD));

CHANGE REPLICATION FILTER 语句仅替换受该语句影响的过滤器类型和复制通道的复制过滤规则,并保持其他规则和通道不变。 如果要取消设置给定类型的所有过滤器,请将过滤器的值设置为显式空列表,如此示例所示,该列表将删除所有现有 REPLICATE_DO_DB REPLICATE_IGNORE_DB 规则:

更换复制过滤器
    REPLICATE_DO_DB =(),REPLICATE_IGNORE_DB =();

以这种方式将过滤器设置为空将删除所有现有规则,不会创建任何新规则,也不会使用 --replicate-* 命令行或配置文件中的选项 恢复在mysqld启动时设置的任何规则

RESET SLAVE ALL 语句删除 语句删除的通道上设置的通道特定复制过滤器。 重新创建删除的一个或多个通道时,会为从属服务器指定的任何全局复制过滤器复制到它们,并且不会应用任何特定于通道的复制过滤器。

有关更多信息,请参见 第17.2.5节“服务器如何评估复制过滤规则”

13.4.2.3 MASTER_POS_WAIT()语法

SELECT MASTER_POS_WAIT(' master_log_file',master_log_pos[,timeout] [,channel])

这实际上是一个函数,而不是一个声明。 它用于确保从站已经读取并执行了主站二进制日志中给定位置的事件。 有关 完整说明, 请参见 第12.24节“其他功能”

13.4.2.4 RESET SLAVE语法

重置从[全部] [ channel_option]

channel_option
    FOR CHANNEL channel

RESET SLAVE 使奴隶忘记其在主二进制日志中的复制位置。 此语句旨在用于干净启动:它清除主信息和中继日志信息存储库,删除所有中继日志文件,并启动新的中继日志文件。 它还将使用 MASTER_DELAY 选项 指定的复制延迟重置为0 CHANGE MASTER TO RESET SLAVE 不会改变 gtid_executed 的值 gtid_purged

注意

所有中继日志文件都被删除,即使它们尚未完全由从属SQL线程执行。 (如果您已发出 STOP SLAVE 语句或从站高负载,则 这是复制从站上可能存在的情况 。)

RESET SLAVE 需要 RELOAD 特权。

要使用 RESET SLAVE ,必须停止从属复制线程,因此 STOP SLAVE 在发布之前 运行的从属用户 RESET SLAVE RESET SLAVE 在组复制组成员上使用,成员状态必须是 OFFLINE ,这意味着已加载插件但该成员当前不属于任何组。 可以使用 STOP GROUP REPLICATION 语句使 组成员脱机

使用optional 子句可以命名该语句适用的复制通道。 提供 子句将 语句 应用于 特定复制通道。 子句与 选项 组合将 删除指定的通道。 如果未命名通道且不存在额外通道,则该语句将应用于默认通道。 当存在多个复制通道时, 发出 不带 子句 语句 会删除 所有 复制通道,并仅重新创建默认通道。 有关 更多信息 请参见 第17.2.3节“复制通道” FOR CHANNEL channel FOR CHANNEL channel RESET SLAVE FOR CHANNEL channel ALL RESET SLAVE ALL FOR CHANNEL channel

RESET SLAVE 不会更改任何复制连接参数,例如主主机,主端口,主用户或主密码。

  • 从MySQL 8.0.13开始,在 master_info_repository=TABLE 服务器上设置时(默认情况下是MySQL 8.0),复制连接参数 作为 操作的 一部分 保存在崩溃安全 InnoDB mysql.slave_master_info RESET SLAVE 它们也保留在记忆中。 如果服务器崩溃或在发出之后 RESET SLAVE 但在发布之前 故意重新启动 START SLAVE ,则从表中检索复制连接参数并重新用于新连接。

  • master_info_repository=FILE 服务器上设置时,复制连接参数仅保留在内存中。 如果 由于服务器崩溃或故意重启而 在发出后立即重新启动 从属 mysqld RESET SLAVE ,则连接参数将丢失。 在这种情况下,您必须 CHANGE MASTER TO 在服务器开始之后 发出 声明,以便在发出之前重新指定连接参数 START SLAVE

如果要有意重置连接参数,则需要使用 RESET SLAVE ALL ,这将清除连接参数。 在这种情况下,必须 CHANGE MASTER TO 在服务器启动后 发出 声明以指定新的连接参数。

RESET SLAVE ALL 清除 IGNORE_SERVER_IDS 设置 列表 CHANGE MASTER TO

RESET SLAVE 不会更改 --replicate-ignore-table 受该语句影响的通道的 任何复制过滤器设置(例如 )。 但是, RESET SLAVE ALL 删除在语句删除的通道上设置的复制筛选器。 重新创建删除的一个或多个通道时,会为从属服务器指定的任何全局复制过滤器复制到它们,并且不会应用任何特定于通道的复制过滤器。 有关更多信息,请参见 第17.2.5.4节“基于复制通道的过滤器”

RESET SLAVE 导致正在进行的事务的隐式提交。 请参见 第13.3.3节“导致隐式提交的语句”

如果从属SQL线程在停止时复制临时表并且 RESET SLAVE 已发出,则会在从属服务器上删除这些复制的临时表。

RESET SLAVE 不重置心跳周期( Slave_heartbeat_period )或 SSL_VERIFY_SERVER_CERT

注意

在NDB群集复制从属SQL节点上使用时, RESET SLAVE 清除该 mysql.ndb_apply_status 表。 使用这种说法时,您应该记住 ndb_apply_status 使用 NDB 存储引擎,因此利用连接到从群集的所有SQL节点共享。

您可以通过 在执行之前 发出来覆盖此行为 ,这可以防止从属程序 在这种情况下 清除 表。 SET GLOBAL @@ndb_clear_apply_status=OFF RESET SLAVE ndb_apply_status

13.4.2.5 SET GLOBAL sql_slave_skip_counter语法

SET GLOBAL sql_slave_skip_counter = N

该语句跳过 N 主服务器 的下一个 事件。 这对于从语句引起的复制停止中恢复非常有用。

仅当从属线程未运行时,此语句才有效。 否则,会产生错误。

使用此语句时,重要的是要了解二进制日志实际上被组织为一组称为 事件组的组 每个事件组由一系列事件组成。

  • 对于事务表,事件组对应于事务。

  • 对于非事务性表,事件组对应于单个SQL语句。

注意

单个事务可以包含对事务和非事务表的更改。

当您使用 SET GLOBAL sql_slave_skip_counter 跳过事件并且结果位于组的中间时,从站会继续跳过事件,直到它到达组的末尾。 然后执行从下一个事件组开始。

13.4.2.6 START SLAVE语法

START SLAVE [ thread_types] [ until_option] [ connection_options] [ channel_option]

thread_types
    [ thread_type[,thread_type] ......]

thread_type
    IO_THREAD | SQL_THREAD

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}

connection_options
    [USER =' user_name'] [PASSWORD =' user_pass'] [DEFAULT_AUTH =' plugin_name'] [PLUGIN_DIR =' plugin_dir']


channel_option
    FOR CHANNEL channel

gtid_setuuid_set[,uuid_set] ......
    | “”

uuid_setuuidinterval[:interval] ...

uuidhhhhhhhh- hhhh- hhhh- hhhh-hhhhhhhhhhhh

h
    [0-9,AF]

intervaln[ - n]
n> = 1)

START SLAVE 没有 thread_type 选项启动两个从属线程。 I / O线程从主服务器读取事件并将它们存储在中继日志中。 SQL线程从中继日志中读取事件并执行它们。 START SLAVE 需要 REPLICATION_SLAVE_ADMIN SUPER 特权。

如果 START SLAVE 成功启动从属线程,则返回时没有任何错误。 但是,即使在这种情况下,也可能是从属线程启动然后停止(例如,因为它们无法连接到主服务器或读取其二进制日志,或其他一些问题)。 START SLAVE 并没有警告你这件事。 您必须检查从站的错误日志以查找从属线程生成的错误消息,或检查它们是否正常运行 SHOW SLAVE STATUS

START SLAVE 导致正在进行的事务的隐式提交。 请参见 第13.3.3节“导致隐式提交的语句”

gtid_next 必须 AUTOMATIC 在发出此声明之前 设置为

使用optional 子句可以命名该语句适用的复制通道。 提供 子句将 语句 应用于 特定复制通道。 如果未命名子句且不存在额外通道,则该语句将应用于默认通道。 如果 语句在使用多个通道时没有定义通道,则此语句将启动所有通道的指定线程。 频道 不允许使用此声明 有关 更多信息 请参见 第17.2.3节“复制通道” FOR CHANNEL channel FOR CHANNEL channel START SLAVE START SLAVE group_replication_recovery

MySQL支持可插拔的用户密码认证 START SLAVE USER PASSWORD DEFAULT_AUTH PLUGIN_DIR 选项,如下面的列表中所述:

  • USER : 用户名。 不能设置为空或空字符串,或者如果 PASSWORD 使用 则保留未设置

  • PASSWORD :密码。

  • DEFAULT_AUTH :插件名称; 默认是MySQL本机身份验证。

  • PLUGIN_DIR :插件的位置。

你不能使用 SQL_THREAD 指定的任何选项时 USER PASSWORD DEFAULT_AUTH ,或者 PLUGIN_DIR ,除非 IO_THREAD 还提供了选项。

有关 更多信息 请参见 第6.2.17节“可插入验证”

如果将不安全的连接与任何这些选项一起使用,则服务器会发出警告警告 在没有SSL / TLS的情况下以纯文本发送密码是非常不安全的

START SLAVE ... UNTIL 支持两个用于全局事务标识符(GTID)的附加选项(请参见 第17.1.3节“使用全局事务标识符复制” )。 其中每个都将一组一个或多个全局事务标识符 gtid_set 作为参数( 有关更多信息, 请参阅 GTID集 )。

如果未 thread_type 指定,则 START SLAVE UNTIL SQL_BEFORE_GTIDS 使从属SQL线程处理事务,直到它到达其中 列出GTID 第一个 事务 gtid_set START SLAVE UNTIL SQL_AFTER_GTIDS 导致从属线程处理所有事务,直到 两个线程都处理了 last 事务 gtid_set 换句话说, START SLAVE UNTIL SQL_BEFORE_GTIDS 导致从属SQL线程处理在到达第一个GTID之前发生的所有事务 gtid_set START SLAVE UNTIL SQL_AFTER_GTIDS 并使从属线程处理所有事务,包括那些在其中找到GTID的事务。 gtid_set ,直到每个人遇到一个GTID不属于该集合的交易。 SQL_BEFORE_GTIDS 并且 SQL_AFTER_GTIDS 每个都支持 SQL_THREAD IO_THREAD 选项,虽然 IO_THREAD 目前 使用 它们没有任何效果。

例如, START SLAVE SQL_THREAD UNTIL SQL_BEFORE_GTIDS = 3E11FA47-71CA-11E1-9E33-C80AA9429562:11-56 使从SQL线程以处理来自其主始发的所有事务 server_uuid 3E11FA47-71CA-11E1-9E33-C80AA9429562 ,直到它遇到具有序列号11中的交易; 然后停止而不处理此事务。 换句话说,处理直到并包括序列号为10的交易的所有交易。 执行 START SLAVE SQL_THREAD UNTIL SQL_AFTER_GTIDS = 3E11FA47-71CA-11E1-9E33-C80AA9429562:11-56 另一方面,会导致从属SQL线程获取刚刚从主服务器提到的所有事务,包括序列号为11到56的所有事务,然后在不处理任何其他事务的情况下停止; 也就是说,序列号为56的事务将是从属SQL线程获取的最后一个事务。

使用带有 slave_preserve_commit_order=0 set 的多线程从站时 ,在以下情况下,从中继日志执行的事务序列中可能存在间隙:

  • 杀死协调员线程

  • 在应用程序线程中发生错误之后

  • mysqld 意外关闭

使用该 START SLAVE UNTIL SQL_AFTER_MTS_GAPS 语句可以使多线程从属的工作线程只运行,直到在中继日志中找不到间隙,然后停止。 此语句可以 SQL_THREAD 选择,但语句的效果保持不变。 它对从属I / O线程没有影响(并且不能与 IO_THREAD 选项 一起使用 )。

发出 START SLAVE 从中继日志执行的事务的序列中具有间隙的多线程从生成警告。 在这种情况下,解决方案是使用 START SLAVE UNTIL SQL_AFTER_MTS_GAPS ,然后发出 RESET SLAVE 删除任何剩余的中继日志。 有关 更多信息 请参见 第17.4.1.33节“复制和事务不一致”

要将失败的多线程从属服务器更改为单线程模式,您可以按所示顺序发出以下一系列语句:

START SLAVE UNTIL SQL_AFTER_MTS_GAPS;

SET @@ GLOBAL.slave_parallel_workers = 0;

开始使用SQL_THREAD;
注意

可以在输出中查看正在运行的 START SLAVE ... 语句 的整个文本 ,包括使用的任何 USER PASSWORD SHOW PROCESSLIST 对于运行 CHANGE MASTER TO 语句 的文本也是如此 ,包括它使用的任何值 MASTER_USER MASTER_PASSWORD

START SLAVE 在I / O线程和SQL线程都已启动后向用户发送确认。 但是,I / O线程可能尚未连接。 出于这个原因,一个成功的 START SLAVE 原因 SHOW SLAVE STATUS 显示 Slave_SQL_Running=Yes ,但这并不保证 Slave_IO_Running=Yes (因为 Slave_IO_Running=Yes 只有I / O线程正在运行 和连接 )。 有关更多信息,请参见 第13.7.6.34节“显示从动状态语法” 第17.1.7.1节“检查复制状态”

您可以 为语句 添加 IO_THREAD SQL_THREAD 选项,以指定要启动的线程。 SQL_THREAD 指定的任选项时不允许 USER PASSWORD DEFAULT_AUTH ,或 PLUGIN_DIR ,除非 IO_THREAD 也被提供选项。

可以添加 一个 UNTIL 子句( until_option 在前面的语法中)来指定从属应该启动和运行,直到SQL线程到达主二进制日志中的给定点,由 MASTER_LOG_POS 和MASTER_LOG_FILE选项 指定 ,或从属中继中的给定点日志,用 RELAY_LOG_POS RELAY_LOG_FILE 选项 表示 当SQL线程到达指定的点时,它将停止。 如果 SQL_THREAD 在语句中指定了 选项,则它仅启动SQL线程。 否则,它启动两个从属线程。 如果SQL线程正在运行, UNTIL 则忽略 子句并发出警告。 您不能使用 UNTIL 带有该 IO_THREAD 选项 子句

也可以 START SLAVE UNTIL 使用其中一个选项指定相对于给定GTID或一组GTID的停止点, SQL_BEFORE_GTIDS 或者 SQL_AFTER_GTIDS 如本节前面所述。 当使用其中的一个选项,您可以指定 SQL_THREAD IO_THREAD ,这两个,或者两者都不是的。 如果仅指定 SQL_THREAD ,则只有从属SQL线程受该语句的影响; 如果仅 IO_THREAD 使用,则仅影响从属I / O. 如果同时使用 SQL_THREAD IO_THREAD 使用它们,或者它们都没有使用,那么SQL和I / O线程都会受到语句的影响。

对于 UNTIL 子句,您必须指定以下任何一项:

  • 这两种 日志文件名,并在文件中的位置

  • 任何 一个 SQL_BEFORE_GTIDS SQL_AFTER_GTIDS

  • SQL_AFTER_MTS_GAPS

不要混合主日志和中继日志选项。 不要将日志文件选项与GTID选项混合使用。

UNTIL 多线程从站不支持 子句,除非同时使用 SQL_AFTER_MTS_GAPS 如果 UNTIL 在没有多线程从站的情况下使用,则从站 SQL_AFTER_MTS_GAPS 以单线程(顺序)模式运行以进行复制,直到 UNTIL 达到 子句 指定的点

任何 UNTIL 条件都由后续 STOP SLAVE 语句, START SLAVE 包含无 UNTIL 子句 语句 或服务器重新启动 重置

指定日志文件和位置时, 即使只有SQL线程受此语句的影响 ,也可以使用该 IO_THREAD 选项 START SLAVE ... UNTIL IO_THREAD 在这种情况下, 选项被忽略。 使用其中一个GTID选项( SQL_BEFORE_GTIDS SQL_AFTER_GTIDS 时,上述限制不适用 ; 在GTID选项支持 SQL_THREAD IO_THREAD ,在本节前面所解释的。

UNTIL 子句可用于调试复制,或导致复制继续进行,直到您希望避免从属服务器复制事件。 例如,如果 DROP TABLE 在主服务器上执行了 一个不明智的 语句,您可以使用它 UNTIL 来告诉从服务器执行到该点但不再执行。 要查找事件的内容, 请将 mysqlbinlog 与主二进制日志或从中继日志一起使用,或使用 SHOW BINLOG EVENTS 语句。

如果您正在使用 UNTIL 从属进程复制的部分查询,则建议您使用 --skip-slave-start 选项启动从服务器,以防止从服务器启动时SQL线程运行。 最好在选项文件中而不是在命令行中使用此选项,以便意外重启服务器不会导致忘记它。

SHOW SLAVE STATUS 语句包括显示 UNTIL 条件 当前值的输出字段

在非常旧版本的MySQL(4.0.5之前)中,调用了此语句 SLAVE START 该语法现在会产生错误。

13.4.2.7 STOP SLAVE语法

STOP SLAVE [ thread_types] [ channel_option]

thread_types
    [ thread_type[,thread_type] ......]

thread_type:IO_THREAD | SQL_THREAD

channel_option
    FOR CHANNEL channel

停止从属线程。 STOP SLAVE 需要 REPLICATION_SLAVE_ADMIN SUPER 特权。 建议的最佳实践是 STOP SLAVE 在停止从服务器之前在从站上执行( 有关更多信息, 请参见 第5.1.17节“服务器关闭过程” )。

使用基于行的日志记录格式时 如果要复制使用非事务性存储引擎的任何表, 则应 在关闭从属服务器之前 执行 STOP SLAVE STOP SLAVE SQL_THREAD 在从属服务器上 执行 (请参阅 本节后面 注释 )。

比如 START SLAVE ,此语句可以与 IO_THREAD SQL_THREAD 选项一起 使用 来命名要停止的线程。

STOP SLAVE 导致正在进行的事务的隐式提交。 请参见 第13.3.3节“导致隐式提交的语句”

gtid_next 必须 AUTOMATIC 在发出此声明之前 设置为

您可以 STOP SLAVE 通过设置 rpl_stop_slave_timeout 系统变量 来控制 超时前等待的时间 这可以用于避免使用 STOP SLAVE 与从属的不同客户端连接 之间的死锁 和其他从属SQL语句 之间的死锁 达到超时值时,发出客户端将返回错误消息并停止等待,但该 STOP SLAVE 指令仍然有效。 一旦从属线程不再忙, STOP SLAVE 则执行 语句并且从属程序停止。

根服务器 CHANGE MASTER TO 运行时允许 一些 语句,具体取决于从属SQL和I / O线程的状态。 但是, 仍然支持在这种情况下 STOP SLAVE 执行之前 使用 CHANGE MASTER TO 有关更多信息 请参见 第13.4.2.1节“更改主语法” 第17.3.8节“在故障转移期间切换主站”

使用optional 子句可以命名该语句适用的复制通道。 提供 子句将 语句 应用于 特定复制通道。 如果未命名通道且不存在额外通道,则该语句将应用于默认通道。 如果 语句在使用多个通道时未命名通道,则此语句将停止所有通道的指定线程。 此声明不能与 频道 一起使用 有关 更多信息 请参见 第17.2.3节“复制通道” FOR CHANNEL channel FOR CHANNEL channel STOP SLAVE STOP SLAVE group_replication_recovery

使用基于语句的复制时 :在主服务器打开临时表时更改主服务器可能不安全。 这是不建议基于语句的临时表复制的原因之一。 您可以通过检查值的值来确定从站上是否有临时表 Slave_open_temp_tables 使用基于语句的复制时,该值在执行前应为0 CHANGE MASTER TO 如果从站上打开了任何临时表,则在发出 CHANGE MASTER TO 声明后发出声明 STOP SLAVE 会导致 ER_WARN_OPEN_TEMP_TABLES_MUST_BE_ZERO 警告。

当使用多线程从属( slave_parallel_workers 非零值)时,从中继日志执行的事务序列中的任何间隙都将作为停止工作线程的一部分而关闭。 如果在 执行语句时 意外停止从属(例如,由于工作线程中的错误或其他线程发出 KILL STOP SLAVE ,则来自中继日志的执行事务序列可能变得不一致。 有关 更多信息 请参见 第17.4.1.33节“复制和事务不一致”

如果当前复制事件组已修改了一个或多个非事务性表,则STOP SLAVE将等待最多60秒以使事件组完成,除非您 为从属SQL线程 发出 KILL QUERY KILL CONNECTION 声明。 如果事件组在超时后仍然不完整,则会记录一条错误消息。

13.4.3用于控制组复制的SQL语句

本节提供有关用于控制组复制的语句的信息。

13.4.3.1 START GROUP_REPLICATION语法

START GROUP_REPLICATION

启动组复制。 此声明需要 GROUP_REPLICATION_ADMIN SUPER 特权。 如果 super_read_only=ON 和成员应作为主要成员加入, super_read_only 则设置为 OFF 成功启动组复制。

13.4.3.2 STOP GROUP_REPLICATION语法

停止GROUP_REPLICATION

停止组复制。 此声明需要 GROUP_REPLICATION_ADMIN SUPER 特权。 一旦您发出 STOP GROUP_REPLICATION 成员设置为 super_read_only=ON ,这将确保在组复制停止时不能对该成员进行写入。 在成员上运行的任何其他复制通道也将停止。

警告

请谨慎使用此语句,因为它会从组中删除服务器实例,这意味着它不再受Group Replication的一致性保证机制的保护。 为了完全安全,请确保在发出此语句之前应用程序无法再连接到实例,以避免任何过时读取的可能性。

13.4.3.3配置组复制主要功能

使用以下功能可以配置单主复制组的哪个成员是主要成员。

  • group_replication_set_as_primary()

    任命该组的特定成员为新的主要成员,压倒任何选举过程。 通过在 member_uuid 这是 server_uuid 要成为新的主成员。 必须在以单主模式运行的复制组的成员上发布。

    句法:

    STRING group_replication_set_as_primary(member_uuid

    返回值:

    包含操作结果的字符串,例如是否成功。

    例:

    SELECT group_replication_set_as_primary(member_uuid

    有关更多信息,请参见 第18.4.2.1节“更改组的主要成员”

13.4.3.4配置组复制模式的功能

使用以下功能可以控制运行复制组的模式,单主模式或多主模式。

  • group_replication_switch_to_single_primary_mode()

    将以多主模式运行的组更改为单主模式,而无需停止组复制。 必须在以多主模式运行的复制组的成员上发布。 当您更改为单主模式时,还会根据单主模式( group_replication_enforce_update_everywhere_checks=OFF )中的 要求禁用所有组成员的严格一致性检查

    句法:

    STRING group_replication_switch_to_single_primary_mode([ str])

    参数:

    • str :包含该组成员的UUID的字符串,该成员应成为新的单个主要成员。 该组的其他成员成为辅助成员。

    返回值:

    包含操作结果的字符串,例如是否成功。

    例:

    SELECT group_replication_switch_to_single_primary_mode(member_uuid);
    

    有关更多信息,请参见 第18.4.2.2节“更改组模式”

  • group_replication_switch_to_multi_primary_mode()

    将以单主模式运行的组更改为多主模式。 必须在以单主模式运行的复制组的成员上发布。

    句法:

    STRING group_replication_switch_to_multi_primary_mode()

    此功能没有参数。

    返回值:

    包含操作结果的字符串,例如是否成功。

    例:

    SELECT group_replication_switch_to_multi_primary_mode()

    属于该组的所有成员都成为初选。

    有关更多信息,请参见 第18.4.2.2节“更改组模式”

13.4.3.5检查和配置组的最大共识实例的功能

以下函数使您可以检查和配置组可以并行执行的最大共识实例数。

13.4.3.6检查和设置组复制通信协议版本的功能

使用以下功能可以检查和配置复制组使用的组复制通信协议版本。

  • group_replication_get_communication_protocol()

    检查当前用于组的组复制通信协议版本。

    句法:

    STRING group_replication_get_communication_protocol()
    

    此功能没有参数。

    返回值:

    最古老的MySQL Server版本,可以加入该组并使用该组的通信协议。 MySQL 5.7.14中的版本允许压缩消息,而MySQL 8.0.16中的版本也允许消息碎片化。 请注意, group_replication_get_communication_protocol() UDF返回该组支持的最小MySQL版本,该版本可能与传递给 group_replication_set_communication_protocol() UDF 的版本号 以及安装在使用UDF的成员上的MySQL Server版本不同。

    如果由于此服务器实例不属于复制组而无法检查协议,则会以字符串形式返回错误。

    例:

    SELECT group_replication_get_communication_protocol();
    + ------------------------------------------------ +
    | group_replication_get_communication_protocol()|
    + ------------------------------------------------ +
    | 8.0.16 |
    + ------------------------------------------------ +
    

    有关更多信息,请参见 第18.4.2.4节“设置组的通信协议版本”

  • group_replication_set_communication_protocol()

    降级组的组复制通信协议版本,以便早期版本的成员可以在所有成员上升级MySQL Server之后加入或升级组的组复制通信协议版本。 GROUP_REPLICATION_ADMIN 使用此UDF需要 权限,并且在发出语句时所有现有组成员必须联机,且不会丢失多数。

    注意

    对于MySQL InnoDB集群,只要使用AdminAPI操作更改集群拓扑,就会自动管理通信协议版本。 您不必自己为InnoDB集群使用这些UDF。

    句法:

    STRING group_replication_set_communication_protocol(version

    参数:

    • version :对于降级,请指定具有最早安装的服务器版本的预期组成员的MySQL Server版本。 在这种情况下,该命令使组回退到与该服务器版本兼容的通信协议(如果可能)。 您可以指定的最小服务器版本是MySQL 5.7.14。 要进行升级,请指定已升级现有组成员的新MySQL服务器版本。

    返回值:

    包含操作结果的字符串,例如是否成功。

    例:

    SELECT group_replication_set_communication_protocol("5.7.25");
    

    有关更多信息,请参见 第18.4.2.4节“设置组的通信协议版本”

13.5准备好的SQL语句语法

MySQL 8.0为服务器端预处理语句提供支持。 此支持利用了高效的客户端/服务器二进制协议。 将带有占位符的预准备语句用于参数值具有以下好处:

  • 每次执行时解析语句的开销更少。 通常,数据库应用程序处理大量几乎相同的语句,只更改子句中的文字或变量值,例如 WHERE 查询和删除, SET 更新和 VALUES 插入。

  • 防止SQL注入攻击。 参数值可以包含未转义的SQL引号和分隔符。

应用程序中的准备语句

您可以通过客户端编程接口使用服务器端预处理语句,包括 MySQL C API客户端库 用于C程序的 MySQL Connector / C 用于Java程序的 MySQL Connector / J 用于使用.NET技术的程序的 MySQL Connector / NET 例如,C API提供了一组函数调用,这些函数调用构成了其准备好的语句API。 请参见 第28.7.8节“C API准备语句” 其他语言接口可以通过在C客户端库中链接来提供对使用二进制协议的预准备语句的支持,其中一个示例是 mysqli 扩展 ,可在PHP 5.0及更高版本中使用。

SQL脚本中的准备语句

可以使用备用语句的备用SQL接口。 此接口不如通过预准备语句API使用二进制协议那样高效,但不需要编程,因为它可直接在SQL级别使用:

  • 当没有可用的编程接口时,您可以使用它。

  • 您可以从任何可以将SQL语句发送到要执行的服务器的程序中使用它,例如 mysql 客户端程序。

  • 只要连接到运行MySQL 4.1或更高版本的服务器,即使客户端使用的是旧版本的客户端库,也可以使用它。

预准备语句的SQL语法旨在用于以下情况:

  • 在编写之前测试准备语句在应用程序中的工作方式。

  • 在无法访问支持它们的编程API时使用预准备语句。

  • 使用预准备语句以交互方式解决应用程序问题。

  • 创建一个用预处理语句重现问题的测试用例,以便您可以提交错误报告。

PREPARE,EXECUTE和DEALLOCATE PREPARE语句

预处理语句的SQL语法基于三个SQL语句:

以下示例显示了两种等效的方法来准备一个语句,该语句根据双方的长度计算三角形的斜边。

第一个示例显示如何使用字符串文字创建预准备语句以提供语句的文本:

mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> SET @a = 3;
mysql> SET @b = 4;
mysql>EXECUTE stmt1 USING @a, @b;
+ ------------ +
| 斜边|
+ ------------ +
| 5 |
+ ------------ +
MySQL的> DEALLOCATE PREPARE stmt1;

第二个示例类似,但提供语句的文本作为用户变量:

mysql> SET @s = 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> PREPARE stmt2 FROM @s;
mysql> SET @a = 6;
mysql> SET @b = 8;
mysql>EXECUTE stmt2 USING @a, @b;
+ ------------ +
| 斜边|
+ ------------ +
| 10 |
+ ------------ +
MySQL的> DEALLOCATE PREPARE stmt2;

下面是另一个示例,演示如何通过将表的名称存储为用户变量来选择在运行时执行查询的表:

mysql> USE test;
mysql> CREATE TABLE t1 (a INT NOT NULL);
mysql>INSERT INTO t1 VALUES (4), (8), (11), (32), (80);

mysql> SET @table = 't1';
mysql>SET @s = CONCAT('SELECT * FROM ', @table);

mysql> PREPARE stmt3 FROM @s;
mysql>EXECUTE stmt3;
+ ---- +
| a |
+ ---- +
| 4 |
| 8 |
| 11 |
| 32 |
| 80 |
+ ---- +

MySQL的> DEALLOCATE PREPARE stmt3;

准备好的语句特定于创建它的会话。 如果在不释放先前准备的语句的情况下终止会话,则服务器会自动解除分配。

准备好的声明也是本届会议的全球性声明。 如果在存储例程中创建预准备语句,则在存储例程结束时不会取消分配。

要防止同时创建太多准备好的语句,请设置 max_prepared_stmt_count 系统变量。 要防止使用预准备语句,请将值设置为0。

准备语句中允许的SQL语法

以下SQL语句可用作预准备语句:

更改表
更改用户
分析表
CACHE INDEX
呼叫
改变主人
CHECKSUM {TABLE | TABLES}
承诺
{创建| DROP} INDEX
{创建| 重命名| DROP} DATABASE
{创建| DROP} TABLE
{创建| 重命名| DROP} USER
{创建| DROP} VIEW
删除
FLUSH {表| 表格| 阅读锁定的表格 HOSTS | 特权
  | LOGS | 状态| MASTER | 奴役| USER_RESOURCES}
GRANT
插入
安装插件
负荷指数进入高速缓存
优化表
重命名表
修理表
更换
重置{MASTER | 奴隶}
撤消
选择
显示{警告| 错误}
展示BINLOG活动
SHOW CREATE {PROCEDURE | 功能| 活动| 表| 视图}
SHOW {MASTER | BINARY} LOGS
SHOW {MASTER | SLAVE}状态
从来没有{开始| 停}
TRUNCATE TABLE
卸载插件
UPDATE

为了符合SQL标准,该标准声明诊断语句是不可伪造的,MySQL不支持以下准备语句:

  • SHOW WARNINGS SHOW COUNT(*) WARNINGS

  • SHOW ERRORS SHOW COUNT(*) ERRORS

  • 包含对任何参考语句 warning_count error_count 系统变量。

MySQL 8.0不支持其他语句。

通常,SQL预处理语句中不允许的语句也不允许存储在程序中。 第C.1节“存储程序的限制” 中注明了例外情况

检测到由预准备语句引用的表或视图的元数据更改,并在下次执行时自动对语句进行表示。 有关更多信息,请参见 第8.10.3节“准备语句和存储程序的缓存”

使用预 LIMIT 准备语句时, 占位符可用于 子句 的参数 请参见 第13.2.10节“SELECT语法”

在准备 CALL 与使用的语句 PREPARE ,并 EXECUTE 为占位符的支持 OUT INOUT 参数可与MySQL 8.0版以后。 有关 早期版本的示例和变通方法, 请参见 第13.2.1节“CALL语法” IN 无论版本如何, 占位符都可用于 参数。

预处理语句的SQL语法不能以嵌套方式使用。 也就是说,传递给一个说法 PREPARE 本身不能成为一个 PREPARE EXECUTE DEALLOCATE PREPARE 声明。

预准备语句的SQL语法与使用预准备语句API调用不同。 例如,您不能使用 mysql_stmt_prepare() C API函数来准备 PREPARE EXECUTE DEALLOCATE PREPARE 声明。

预准备语句的SQL语法可以在存储过程中使用,但不能在存储的函数或触发器中使用。 然而,光标不能用于被制备并用执行的动态语句 PREPARE EXECUTE 在游标创建时检查游标的语句,因此该语句不能是动态的。

预处理语句的SQL语法不支持多语句(即,由 ; 字符 分隔的单个字符串中的多个语句 )。

要编写使用 CALL SQL语句执行包含预准备语句的存储过程的 C程序, CLIENT_MULTI_RESULTS 必须启用 标志。 这是因为 CALL 除了过程中执行的语句可能返回的任何结果集之外, 每个都 返回一个结果来指示调用状态。

CLIENT_MULTI_RESULTS 可以在调用时启用 mysql_real_connect() ,可以通过传递 CLIENT_MULTI_RESULTS 标志本身 显式 启用 ,也可以通过传递 隐式 CLIENT_MULTI_STATEMENTS 启用(也可以启用 CLIENT_MULTI_RESULTS )。 有关其他信息,请参见 第13.2.1节“CALL语法”

13.5.1 PREPARE语法

准备stmt_name来自preparable_stmt

PREPARE 语句准备一个SQL语句并为其指定一个名称, stmt_name 以便稍后引用该语句。 准备语句是与执行 EXECUTE 与发布 DEALLOCATE PREPARE 有关示例,请参见 第13.5节“准备的SQL语句语法”

语句名称不区分大小写。 preparable_stmt 是字符串文字或包含SQL语句文本的用户变量。 文本必须表示单个语句,而不是多个语句。 在语句中, ? 字符可以用作参数标记,以指示稍后在执行时将数据值绑定到查询的位置。 ? 字符不应引号括起来,即使你打算将它们绑定到字符串值。 参数标记只能用于应出现数据值的位置,而不能用于SQL关键字,标识符等。

如果已存在具有给定名称的预准备语句,则在准备新语句之前将其隐式释放。 这意味着如果新语句包含错误且无法准备,则会返回错误,并且不存在具有给定名称的语句。

准备好的声明的范围是创建声明的会话,其中包含以下几个含义:

  • 在一个会话中创建的预准备语句不可用于其他会话。

  • 会话结束时,无论是正常还是异常,其准备好的陈述不再存在。 如果启用了自动重新连接,则不会通知客户端连接已丢失。 因此,客户可能希望禁用自动重新连接。 请参见 第28.7.28节“C API自动重新连接控制”

  • 在程序完成执行后,在存储程序中创建的预准备语句继续存在,并且可以在程序之后执行。

  • 在存储程序上下文中准备的语句不能引用存储过程或函数参数或局部变量,因为它们在程序结束时超出范围并且将在程序之外稍后执行的语句将不可用。 作为一种解决方法,请转而使用具有会话范围的用户定义变量; 请参见 第9.4节“用户定义的变量”

13.5.2 EXECUTE语法

执行stmt_name
    [使用@ var_name[,@ var_name] ...]

在准备好语句之后 ,使用引用预准备语句名称 PREPARE EXECUTE 语句 执行它 如果预准备语句包含任何参数标记,则必须提供一个 USING 子句, 子句列出包含要绑定到参数的值的用户变量。 参数值只能由用户变量提供,并且该 USING 子句的名称必须与语句中参数标记的数量完全相同。

您可以多次执行给定的预准备语句,将不同的变量传递给它,或者在每次执行之前将变量设置为不同的值。

有关示例,请参见 第13.5节“准备的SQL语句语法”

13.5.3 DEALLOCATE PREPARE语法

{DEALLOCATE | DROP} PREPAREstmt_name

要解除分配生成的预准备语句 PREPARE ,请使用 DEALLOCATE PREPARE 引用预准备语句名称的语句。 在解除分配后尝试执行预准备语句会导致错误。 如果创建了太多准备好的语句,并且未通过 DEALLOCATE PREPARE 语句或会话结束 解除分配 ,则可能会遇到 max_prepared_stmt_count 系统变量 强制执行的上限

有关示例,请参见 第13.5节“准备的SQL语句语法”

13.6复合语句语法

本节介绍 BEGIN ... END 复合语句 的语法 以及可在存储程序体中使用的其他语句:存储过程和函数,触发器和事件。 这些对象是根据存储在服务器上以供以后调用的SQL代码定义的(请参阅 第24章, 存储对象 )。

复合语句是一个可以包含其他块的块; 变量,条件处理程序和游标的声明; 和流控制结构,如循环和条件测试。

13.6.1 BEGIN ... END复合语句语法

[begin_label:]开始
    [statement_list]
结束[ end_label]

BEGIN ... END 语法用于编写复合语句,它可以出现在存储的程序(存储过程和函数,触发器和事件)中。 复合语句可以包含多个语句,由 BEGIN END 关键字 括起来 statement_list 表示一个或多个语句的列表,每个语句以semicolon( ; )语句分隔符 结尾 statement_list 本身是可选的,因此空的复合语句( BEGIN END )是合法的。

BEGIN ... END 块可以嵌套。

使用多个语句要求客户端能够发送包含 ; 语句分隔符的 语句字符串 mysql 命令行客户端中,使用该 delimiter 命令 处理 更改 ; 语句结束分隔符(例如,to // )允许 ; 在程序体中使用。 有关示例,请参见 第24.1节“定义存储程序”

BEGIN ... END 块可以被标记。 请参见 第13.6.2节“语句标签语法”

[NOT] ATOMIC 不支持 可选 子句。 这意味着在指令块的开头没有设置事务保存点,并且 BEGIN 此上下文中使用 子句对当前事务没有影响。

注意

在所有存储的程序中,解析器将其 BEGIN [WORK] 视为 BEGIN ... END 的开头 要在此上下文中开始事务,请 START TRANSACTION 改用。

13.6.2语句标签语法

[begin_label:]开始
    [statement_list]
结束[ end_label]

[ begin_label:] LOOP
     statement_list
END LOOP [ end_label]

[ begin_label:] REPEAT
     statement_list
直到search_condition
END REPEAT [ end_label]

[ begin_label:] WHILE search_conditionDO
     statement_list
END WHILE [ end_label]

标签被允许 BEGIN ... END 块和对 LOOP REPEAT WHILE 语句。 这些语句的标签用法遵循以下规则:

  • begin_label 必须跟着冒号。

  • begin_label 可以没有 end_label 如果 end_label 存在,则必须与...相同 begin_label

  • end_label 不能没有 begin_label

  • 同一嵌套级别的标签必须是不同的。

  • 标签最长可达16个字符。

要引用标记构造中的标签,请使用 ITERATE LEAVE 声明。 以下示例使用这些语句继续迭代或终止循环:

CREATE PROCEDURE doiterate(p1 INT)
开始
  label1:LOOP
    SET p1 = p1 + 1;
    如果p1 <10那么ITERATE label1; 万一;
    LEAVE label1;
  END LOOP label1;
结束;

块标签的范围不包括块内声明的处理程序的代码。 有关详细信息,请参见 第13.6.7.2节“DECLARE ... HANDLER语法”

13.6.3 DECLARE语法

DECLARE 语句用于定义程序本地的各种项目:

DECLARE 只允许在 BEGIN ... END 复合语句中使用,并且在任何其他语句之前必须在其开头。

声明必须遵循一定的顺序。 游标声明必须出现在处理程序声明之前。 变量和条件声明必须出现在游标或处理程序声明之前。

13.6.4存储程序中的变量

系统变量和用户定义的变量可以在存储的程序中使用,就像它们可以在存储程序上下文之外使用一样。 此外,存储的程序可用于 DECLARE 定义局部变量,并且可以声明存储的例程(过程和函数)以获取在例程与其调用者之间传递值的参数。

有关局部变量范围以及MySQL如何解析模糊名称的信息,请参见 第13.6.4.2节“局部变量范围和分辨率”

不允许将值分配 DEFAULT 给存储过程或函数参数或存储的程序局部变量(例如,使用 语句)。 在MySQL 8.0中,这会导致语法错误。 SET var_name = DEFAULT

13.6.4.1本地变量DECLARE语法

DECLARE var_name[,var_name] ... type[DEFAULT value]

此语句声明存储程序中的局部变量。 要为变量提供默认值,请包含 DEFAULT 子句。 该值可以指定为表达式; 它不一定是常数。 如果 DEFAULT 缺少 子句,则初始值为 NULL

局部变量被视为关于数据类型和溢出检查的存储例程参数。 请参见 第13.1.17节“创建过程和创建函数语法”

变量声明必须出现在游标或处理程序声明之前。

局部变量名称不区分大小写。 允许的字符和引用规则与其他标识符相同,如 第9.2节“架构对象名称”中所述

局部变量的 BEGIN ... END 范围是声明它 块。 除了那些声明具有相同名称的变量的块之外,可以在嵌套在声明块中的块中引用该变量。

有关变量声明的示例,请参见 第13.6.4.2节“局部变量范围和分辨率”

13.6.4.2局部变量范围和分辨率

局部变量的 BEGIN ... END 范围是声明它 块。 除了那些声明具有相同名称的变量的块之外,可以在嵌套在声明块中的块中引用该变量。

由于局部变量仅在存储程序执行期间在范围内,因此在存储程序中创建的预准备语句中不允许引用它们。 准备好的语句范围是当前会话,而不是存储的程序,因此语句可以在程序结束后执行,此时变量将不再在范围内。 例如, 不能用作预备语句。 此限制也适用于存储过程和函数参数。 请参见 第13.5.1节“PREPARE语法” SELECT ... INTO local_var

局部变量不应与表列具有相同的名称。 如果SQL语句(如 SELECT ... INTO 语句)包含对列的引用和声明的具有相同名称的局部变量,则MySQL当前会将引用解释为变量的名称。 请考虑以下过程定义:

CREATE PROCEDURE sp1(x VARCHAR(5))
开始
  DECLARE xname VARCHAR(5)DEFAULT'bob';
  DECLARE newname VARCHAR(5);
  DECLARE xid INT;

  SELECT xname,id INTO newname,xid
    FROM table1 WHERE xname = xname;
  SELECT newname;
结束;

MySQL解释 xname SELECT 语句中将其 为对 xname 变量 的引用 而不是 xname 因此,在 sp1() 调用 过程时 无论 newname 的值 'bob' 如何, 变量都会返回值 table1.xname

同样,以下过程中的游标定义包含 SELECT 引用 语句 xname MySQL将此解释为对该名称的变量的引用,而不是列引用。

CREATE PROCEDURE sp2(x VARCHAR(5))
开始
  DECLARE xname VARCHAR(5)DEFAULT'bob';
  DECLARE newname VARCHAR(5);
  DECLARE xid INT;
  DECLARE完成了TINYINT DEFAULT 0;
  DECLARE cur1 CURSOR FOR SELECT xname,id FROM table1;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

  打开cur1;
  read_loop:LOOP
    FETCH FROM cur1 INTO newname,xid;
    如果完成那么就是read_loop; 万一;
    SELECT newname;
  结束循环;
  关闭cur1;
结束;

另请参见 第C.1节“存储程序的限制”

13.6.5流量控制声明

MySQL的支持 IF CASE ITERATE ,并 构建了存储程序中的流量控制。 它还支持 存储的功能。 LEAVE LOOP WHILE REPEAT RETURN

其中许多构造包含其他语句,如以下部分中的语法规范所示。 这样的构造可以嵌套。 例如, IF 语句可能包含一个 WHILE 循环,它本身包含一个 CASE 语句。

MySQL不支持 FOR 循环。

13.6.5.1 CASE语法

CASE case_value
    WHEN when_valueTHEN statement_list
    [WHEN when_valueTHENstatement_list ] ...
    [其他 statement_list ]
结束案例

要么:

案件
    WHEN search_conditionTHEN statement_list
    [WHEN search_conditionTHENstatement_list ] ...
    [其他 statement_list ]
结束案例

CASE 存储程序 语句实现了复杂的条件构造。

注意

还有一个 expr ,它与 此处描述 语句 不同 请参见 第12.4节“控制流功能” 语句不能有一个 子句,它以for 而不是 CASE CASE CASE ELSE NULL END CASE END

对于第一种语法, case_value 是表达式。 将此值与 when_value 每个 WHEN 子句中 表达式进行 比较, 直到其中一个相等。 when_value 找到 相等 THEN 子句时, statement_list 执行 相应的 子句 如果no不 when_value 相等,则 执行 ELSE 子句 statement_list (如果有)。

此语法不能用于测试相等性, NULL 因为它 NULL = NULL 是false。 请参见 第3.3.4.6节“使用NULL值”

对于第二种语法, 将评估 每个 WHEN 子句 search_condition 表达式,直到其中一个为真,此时它的相应 THEN 子句将 statement_list 执行。 如果no不 search_condition 相等,则 执行 ELSE 子句 statement_list (如果有)。

如果没有 when_value search_condition 匹配测试的值且该 CASE 语句不包含 ELSE 子句,则 找不到CASE语句 错误结果 Case

每个 statement_list 包含一个或多个SQL语句; statement_list 不允许

要处理任何 WHEN 子句都 没有匹配值的情况 ,请使用 ELSE 包含空 BEGIN ... END 块的情况,如本例所示。 (本 ELSE 条款中 使用的缩进仅用于 清晰的目的,并不重要。)

DELIMITER |

CREATE PROCEDURE p()
  开始
    DECLARE v INT DEFAULT 1;

    案例v
      当2那么选择v;
      当3然后选择0;
      其他
        开始
        结束;
    结束案例;
  结束;
  |

13.6.5.2 IF语法

如果search_condition那么statement_list
    [ELSEIF search_condition那么statement_list] ......
    [ELSEstatement_list ]
万一

IF 存储程序 语句实现了一个基本的条件结构。

注意

还有一个 函数 ,它与 此处描述 语句 不同 请参见 第12.4节“控制流功能” 语句可以包含 条款,并以终止 IF() IF IF THEN ELSE ELSEIF END IF

如果给定的 search_condition 计算结果为true,则 执行 相应的 THEN or ELSEIF 子句 statement_list 如果不 search_condition 匹配,则 执行 ELSE 子句 statement_list

每个 statement_list 包含一个或多个SQL语句; statement_list 不允许

IF ... END IF 存储程序中使用的所有其他流控制块一样,块必须以分号结束,如下例所示:

DELIMITER //

创建函数SimpleCompare(n INT,m INT)
  退货车(20)

  开始
    DECLARE s VARCHAR(20);

    如果n> m那么设置s ='>';
    ELSEIF n = m THEN SET s ='=';
    ELSE SET s ='<';
    万一;

    SET s = CONCAT(n,'',s,'',m);

    返回;
  结束 //

DELIMITER;

与其他流控制结构一样, IF ... END IF 块可以嵌套在其他流控制结构中,包括其他 IF 语句。 每个 IF 必须由它自己终止, END IF 然后是分号。 您可以使用缩进来使嵌套的流控制块更容易被人类读取(尽管MySQL不需要这样),如下所示:

DELIMITER //

CREATE FUNCTION VerboseCompare(n INT,m INT)
  返回VARCHAR(50)

  开始
    DECLARE s VARCHAR(50);

    IF n = m THEN SET s ='equals';
    其他
      如果n> m那么SET s ='更大';
      ELSE SET s ='less';
      万一;

      SET s = CONCAT('是',s,'比');
    万一;

    SET s = CONCAT(n,'',s,'',m,'。');

    返回;
  结束 //

DELIMITER;

在此示例中, IF 仅在 n 不等于 内部 时才计算 内部 m

13.6.5.3 ITERATE语法

重复 label

ITERATE 只能出现 LOOP REPEAT WHILE 语句。 ITERATE 意思是 再次开始循环。

有关示例,请参见 第13.6.5.5节“LOOP语法”

13.6.5.4 LEAVE语法

离开 label

此语句用于退出具有给定标签的流控制结构。 如果标签用于最外面存储的程序块,则 LEAVE 退出程序。

LEAVE 可以内使用 BEGIN ... END 或循环结构( LOOP REPEAT WHILE )。

有关示例,请参见 第13.6.5.5节“LOOP语法”

13.6.5.5 LOOP语法

[ begin_label:] LOOP
     statement_list
END LOOP [ end_label]

LOOP 实现一个简单的循环结构,允许重复执行语句列表,该列表由一个或多个语句组成,每个语句以semicolon( ; )语句分隔符结束。 循环中的语句将重复,直到循环终止。 通常,这是通过 LEAVE 声明 来完成的 在存储的函数中, RETURN 也可以使用,它完全退出函数。

忽略包含循环终止语句会导致无限循环。

一个 LOOP 语句可以被标记。 有关标签使用的规则,请参见 第13.6.2节“语句标签语法”

例:

CREATE PROCEDURE doiterate(p1 INT)
开始
  label1:LOOP
    SET p1 = p1 + 1;
    如果p1 <10那么
      ITERATE label1;
    万一;
    LEAVE label1;
  END LOOP label1;
  SET @x = p1;
结束;

13.6.5.6 REPEAT语法

[ begin_label:] REPEAT
     statement_list
直到search_condition
END REPEAT [ end_label]

语句中的语句列表 REPEAT 将重复,直到 search_condition 表达式为true。 因此, REPEAT 总是至少进入一次循环。 statement_list 由一个或多个语句组成,每个语句以semicolon( ; )语句分隔符 结尾

一个 REPEAT 语句可以被标记。 有关标签使用的规则,请参见 第13.6.2节“语句标签语法”

例:

MySQL的> delimiter //

MySQL的> CREATE PROCEDURE dorepeat(p1 INT)
       BEGIN
         SET @x = 0;
         REPEAT
           SET @x = @x + 1;
         UNTIL @x > p1 END REPEAT;
       END
       //
查询正常,0行受影响(0.00秒)

MySQL的> CALL dorepeat(1000)//
查询正常,0行受影响(0.00秒)

MySQL的> SELECT @x//
+ ------ +
| @x |
+ ------ +
| 1001 |
+ ------ +
1排(0.00秒)

13.6.5.7 RETURN语法

返回 expr

RETURN 语句终止存储函数的执行并将值返回 expr 给函数调用者。 RETURN 存储函数中 必须至少有一个 语句。 如果函数有多个退出点,则可能有多个。

此语句不用于存储过程,触发器或事件。 LEAVE 语句可用于退出这些类型的存储程序。

13.6.5.8 WHILE语法

[ begin_label:] WHILE search_conditionDO
     statement_list
END WHILE [ end_label]

WHILE 只要 search_condition 表达式为true ,语句中的语句列表 就会重复 statement_list 由一个或多个SQL语句组成,每个语句都以semicolon( ; )语句分隔符结束。

一个 WHILE 语句可以被标记。 有关标签使用的规则,请参见 第13.6.2节“语句标签语法”

例:

CREATE PROCEDURE dowhile()
开始
  DECLARE v1 INT DEFAULT 5;

  WHILE v1> 0 DO
    ...
    SET v1 = v1  -  1;
  结束时间;
结束;

13.6.6游标

MySQL支持存储程序中的游标。 语法与嵌入式SQL中的一样。 游标具有以下属性:

  • 敏感:服务器可能会也可能不会复制其结果表

  • 只读:不可更新

  • 不可滚动:只能在一个方向上遍历,不能跳过行

游标声明必须出现在处理程序声明之前以及变量和条件声明之后。

例:

CREATE PROCEDURE curdemo()
开始
  DECLARE完成INT DEFAULT FALSE;
  宣布CHAR(16);
  DECLARE b,c INT;
  DECLARE cur1 CURSOR FOR SELECT id,data FROM test.t1;
  DECLARE cur2 CURSOR FOR SELECT i FROM test.t2;
  DECLARE CONTINUE HANDLER for NOT FOUND SET done = TRUE;

  打开cur1;
  打开cur2;

  read_loop:LOOP
    FETCH cur1 INTO a,b;
    FETCH cur2 INTO c;
    如果这样做了
      LEAVE read_loop;
    万一;
    如果b <c那么
      INSERT INTO test.t3 VALUES(a,b);
    其他
      INSERT INTO test.t3 VALUES(a,c);
    万一;
  结束循环;

  关闭cur1;
  关闭cur2;
结束;

13.6.6.1光标CLOSE语法

cursor_name

该语句关闭先前打开的游标。 有关示例,请参见 第13.6.6节“游标”

如果光标未打开,则会发生错误。

如果未显式关闭 BEGIN ... END ,则在声明它 的末尾关闭游标

13.6.6.2游标DECLARE语法

DECLARE cursor_nameCURSOR FORselect_statement

此语句声明游标并将其与一个 SELECT 语句 相关联,该 语句检索游标要遍历的行。 要稍后获取行,请使用 FETCH 语句。 SELECT 语句 检索的列数 必须与语句中指定的输出变量数相匹配 FETCH

SELECT 语句不能有一个 INTO 条款。

游标声明必须出现在处理程序声明之前以及变量和条件声明之后。

存储的程序可能包含多个游标声明,但在给定块中声明的每个游标必须具有唯一的名称。 有关示例,请参见 第13.6.6节“游标”

对于通过 SHOW 语句 提供的信息 ,在许多情况下可以通过使用带有 INFORMATION_SCHEMA 的游标来获得等效信息

13.6.6.3游标FETCH语法

FETCH [[NEXT] FROM] cursor_nameINTO var_name[,var_name] ......

此语句将获取下一行 SELECT 与指定游标关联 语句 (必须打开),并使光标指针前进。 如果存在行,则获取的列将存储在命名变量中。 SELECT 语句 检索的列数 必须与语句中指定的输出变量数相匹配 FETCH

如果没有更多行可用,则SQLSTATE值将出现No Data条件 '02000' 要检测此情况,您可以为它(或 NOT FOUND 条件) 设置处理程序 有关示例,请参见 第13.6.6节“游标”

请注意,另一个操作(例如a SELECT 或其他操作 FETCH )也可能通过引发相同的条件来使处理程序执行。 如果有必要区分哪个操作引发了条件,则将操作放在其自己的 BEGIN ... END 块中,以便它可以与其自己的处理程序相关联。

13.6.6.4游标OPEN语法

打开 cursor_name

该语句打开先前声明的游标。 有关示例,请参见 第13.6.6节“游标”

13.6.7条件处理

在存储的程序执行期间可能出现需要特殊处理的条件,例如退出当前程序块或继续执行。 可以针对一般条件(例如警告或异常)或特定条件(例如特定错误代码)定义处理程序。 可以为特定条件指定名称并在处理程序中以这种方式引用。

要命名条件,请使用该 DECLARE ... CONDITION 语句。 要声明处理程序,请使用该 DECLARE ... HANDLER 语句。 请参见 第13.6.7.1节“DECLARE ... CONDITION语法” 第13.6.7.2节“DECLARE ... HANDLER语法” 有关服务器在发生条件时如何选择处理程序的信息,请参见 第13.6.7.6节“处理程序的范围规则”

要提出条件,请使用该 SIGNAL 语句。 要修改条件处理程序中的条件信息,请使用 RESIGNAL 请参见 第13.6.7.1节“DECLARE ... CONDITION语法” 第13.6.7.2节“DECLARE ... HANDLER语法”

要从诊断区域检索信息,请使用该 GET DIAGNOSTICS 语句(请参见 第13.6.7.3节“获取诊断语法” )。 有关诊断区域的信息,请参见 第13.6.7.7节“MySQL诊断区域”

13.6.7.1 DECLARE ... CONDITION语法

申请condition_name条件condition_value

condition_value:{
     mysql_error_code
  | SQLSTATE [VALUE]sqlstate_value
}

DECLARE ... CONDITION 语句声明了一个命名错误条件,将名称与需要特定处理的条件相关联。 该名称可在后续 DECLARE ... HANDLER 语句中 引用 (请参见 第13.6.7.2节“DECLARE ... HANDLER语法” )。

条件声明必须出现在游标或处理程序声明之前。

condition_value 用于 DECLARE ... CONDITION 指示条件与条件名称关联的特定条件或类。 它可以采取以下形式:

  • mysql_error_code :表示MySQL错误代码的整数文字。

    不要使用MySQL错误代码0,因为它表示成功而不是错误条件。 有关MySQL错误代码的列表,请参见 第B.3.1节“服务器错误消息参考”

  • SQLSTATE [VALUE] sqlstate_value :一个5个字符的字符串文字,表示SQLSTATE值。

    不要使用以开头的SQLSTATE值, '00' 因为这些 表示成功而不是错误条件。 有关SQLSTATE值的列表,请参见 第B.3.1节“服务器错误消息参考”

SIGNAL 或使用 RESIGNAL 语句中 引用的条件名称 必须与SQLSTATE值相关联,而不是与MySQL错误代码相关联。

使用条件名称可以帮助使存储的程序代码更清晰。 例如,此处理程序适用于删除不存在的表的尝试,但只有当您知道1051是 未知表 的MySQL错误代码时才会显现

宣布继续使用1051的HANDLER
  开始
    - 处理者的身体
  结束;

通过声明条件的名称,更容易看到处理程序的目的:

DECLARE no_such_table 1051条件;
为no_such_table声明CONTINUE HANDLER
  开始
    - 处理者的身体
  结束;

以下是相同条件的命名条件,但是基于相应的SQLSTATE值而不是MySQL错误代码:

为SQLSTATE'42S02'声明no_such_table条件;
为no_such_table声明CONTINUE HANDLER
  开始
    - 处理者的身体
  结束;

13.6.7.2 DECLARE ... HANDLER语法

宣布 handler_action HANDLER
    FOR condition_value[,condition_value] ......
    statement

handler_action:{
    继续
  | 出口
  | UNDO
}

condition_value:{
     mysql_error_code
  | SQLSTATE [VALUE] sqlstate_value
  |condition_name
  | SQLWARNING
  | 未找到
  | SQLEXCEPTION
}

DECLARE ... HANDLER 语句指定处理一个或多个条件的处理程序。 如果出现这些条件之一,则 statement 执行 指定的操作 statement 可以是一个简单的语句,例如 ,或使用 编写的复合语句 (参见 第13.6.1节“BEGIN ... END复合语句语法” )。 SET var_name = value BEGIN END

处理程序声明必须出现在变量或条件声明之后。

handler_action 值指示执行处理程序语句后处理程序执行的操作:

  • CONTINUE :继续执行当前程序。

  • EXIT :执行终止为 BEGIN ... END 声明处理程序 复合语句。 即使条件发生在内部块中也是如此。

  • UNDO : 不支持。

condition_value 用于 DECLARE ... HANDLER 表明激活处理程序中的特定条件或一类的条件。 它可以采取以下形式:

  • mysql_error_code :一个整数文字,表示MySQL错误代码,例如1051指定 未知表

    宣布继续使用1051的HANDLER
      开始
        - 处理者的身体
      结束;
    

    不要使用MySQL错误代码0,因为它表示成功而不是错误条件。 有关MySQL错误代码的列表,请参见 第B.3.1节“服务器错误消息参考”

  • SQLSTATE [VALUE] sqlstate_value :一个5个字符的字符串文字,表示SQLSTATE值,例如 '42S01' 指定 unknown table

    为SQLSTATE'42S02'声明继续HANDLER
      开始
        - 处理者的身体
      结束;
    

    不要使用以开头的SQLSTATE值, '00' 因为这些 表示成功而不是错误条件。 有关SQLSTATE值的列表,请参见 第B.3.1节“服务器错误消息参考”

  • condition_name :先前使用的条件名称 DECLARE ... CONDITION 条件名称可以与MySQL错误代码或SQLSTATE值相关联。 请参见 第13.6.7.1节“DECLARE ... CONDITION语法”

  • SQLWARNING :以SQLSTATE值开头的类的简写 '01'

    用于SQLWARNING的DECLARE CONTINUE HANDLER
      开始
        - 处理者的身体
      结束;
    
  • NOT FOUND :以SQLSTATE值开头的类的简写 '02' 这与游标的上下文相关,用于控制光标到达数据集末尾时发生的情况。 如果没有更多行可用,则SQLSTATE值将出现No Data条件 '02000' 要检测此情况,您可以为其或 NOT FOUND 条件 设置处理程序

    DECLARE CONTINUE HANDLER未找到
      开始
        - 处理者的身体
      结束;
    

    有关另一个示例,请参见 第13.6.6节“游标” NOT FOUND 对于 不检索任何行的语句, 也会出现 这种 情况 SELECT ... INTO var_list

  • SQLEXCEPTION :速记类SQLSTATE值不开头 '00' '01' '02'

    DECLARE CONTINUE HANDLER用于SQLEXCEPTION
      开始
        - 处理者的身体
      结束;
    

有关服务器在发生条件时如何选择处理程序的信息,请参见 第13.6.7.6节“处理程序的范围规则”

如果发生没有声明处理程序的条件,则采取的操作取决于条件类:

  • 对于 SQLEXCEPTION 条件,存储的程序终止于引发条件的语句,就像有一个 EXIT 处理程序一样。 如果程序被另一个存储程序调用,则调用程序使用应用于其自己的处理程序的处理程序选择规则来处理该条件。

  • 对于 SQLWARNING 条件,程序继续执行,就像有一个 CONTINUE 处理程序一样。

  • 对于 NOT FOUND 条件,如果条件正常提升,则动作是 CONTINUE 如果是由 SIGNAL or 提出的 RESIGNAL ,那么行动就是 EXIT

以下示例使用处理程序 SQLSTATE '23000' ,出现重复键错误:

MySQL的> CREATE TABLE test.t (s1 INT, PRIMARY KEY (s1));
查询正常,0行受影响(0.00秒)

MySQL的> delimiter //

MySQL的> CREATE PROCEDURE handlerdemo ()
       BEGIN
         DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @x2 = 1;
         SET @x = 1;
         INSERT INTO test.t VALUES (1);
         SET @x = 2;
         INSERT INTO test.t VALUES (1);
         SET @x = 3;
       END;
       //
查询正常,0行受影响(0.00秒)

MySQL的> CALL handlerdemo()//
查询正常,0行受影响(0.00秒)

MySQL的> SELECT @x//
    + ------ +
    | @x |
    + ------ +
    | 3 |
    + ------ +
    1排(0.00秒)

注意 @x 3 在过程执行之后,这表明执行继续该过程的结束发生错误之后。 如果该 DECLARE ... HANDLER 语句不存在,MySQL会 因为 约束 EXIT 在第二次 INSERT 失败 采取默认的action( PRIMARY KEY ,并且 SELECT @x 会返回 2

要忽略条件,请 CONTINUE 为其 声明 处理程序并将其与空块关联。 例如:

用于SQLWARNING的DECLARE CONTINUE HANDLER开始结束;

块标签的范围不包括块内声明的处理程序的代码。 因此,与处理程序关联的语句不能使用 ITERATE LEAVE 引用包含处理程序声明的块的标签。 请考虑以下示例,其中 REPEAT 块的标签为 retry

CREATE PROCEDURE p()
开始
  DECLARE i INT DEFAULT 3;
  重试:
    重复
      开始
        用于SQLWARNING的DECLARE CONTINUE HANDLER
          开始
            ITERATE重试; #违法
          结束;
        如果我<0那么
          LEAVE重试; #legal
        万一;
        SET i = i  -  1;
      结束;
    直到最后重复;
结束;

retry 标签的范围是在 IF 块内声明。 它不在 CONTINUE 处理程序的 范围内 ,因此引用无效并导致错误:

ERROR 1308(42000):LEAVE没有匹配的标签:重试

要避免在处理程序中引用外部标签,请使用以下策略之一:

  • 要离开块,请使用 EXIT 处理程序。 如果不需要块清理,则 BEGIN ... END 处理程序主体可以为空:

    用于SQLWARNING的DECLARE EXIT HANDLER开始结束;
    

    否则,将清理语句放在处理程序体中:

    用于SQLWARNING的DECLARE EXIT HANDLER
      开始
        block cleanup statements
      结束;
    
  • 要继续执行,请在 CONTINUE 可在封闭块中检查 处理程序中 设置状态变量, 以确定是否已调用处理程序。 以下示例将此变量 done 用于此目的:

    CREATE PROCEDURE p()
    开始
      DECLARE i INT DEFAULT 3;
      DECLARE完成INT DEFAULT FALSE;
      重试:
        重复
          开始
            用于SQLWARNING的DECLARE CONTINUE HANDLER
              开始
                SET done = TRUE;
              结束;
            如果完成或者我<0那么
              LEAVE重试;
            万一;
            SET i = i  -  1;
          结束;
        直到最后重复;
    结束;
    

13.6.7.3获取诊断语法

获取[当前| 堆积]诊断
{
    statement_information_item
    [,statement_information_item] ......
  | 条件
    [,] ......condition_number
    condition_information_itemcondition_information_item
}

statement_information_itemtarget=statement_information_item_name

condition_information_itemtarget=condition_information_item_name

statement_information_item_name
  | ROW_COUNT

condition_information_item_name:{
    CLASS_ORIGIN
  | SUBCLASS_ORIGIN
  | RETURNED_SQLSTATE
  | MESSAGE_TEXT
  | MYSQL_ERRNO
  | CONSTRAINT_CATALOG
  | CONSTRAINT_SCHEMA
  | CONSTRAINT_NAME
  | CATALOG_NAME
  | SCHEMA_NAME
  | TABLE_NAME
  | COLUMN_NAME
  | CURSOR_NAME
}

condition_numbertarget
    (见下面的讨论)

SQL语句生成填充诊断区域的诊断信息。 GET DIAGNOSTICS 语句使应用程序可以检查此信息。 (您也可以使用 SHOW WARNINGS SHOW ERRORS 查看条件或错误。)

执行时无需特殊权限 GET DIAGNOSTICS

关键字 CURRENT 表示从当前诊断区域检索信息。 关键字 STACKED 表示从第二个诊断区域检索信息,该信息仅在当前上下文是条件处理程序时可用。 如果没有给出关键字,则默认使用当前诊断区域。

GET DIAGNOSTICS 语句通常用于存储程序中的处理程序。 它是一个MySQL扩展, GET [CURRENT] DIAGNOSTICS 允许在处理程序上下文之外检查任何SQL语句的执行。 例如,如果调用 mysql 客户端程序,则可以在提示符下输入以下语句:

MySQL的> DROP TABLE test.no_such_table;
ERROR 1051(42S02):未知表'test.no_such_table'
mysql> 
mysql>GET DIAGNOSTICS CONDITION 1
         @p1 = RETURNED_SQLSTATE, @p2 = MESSAGE_TEXT;SELECT @p1, @p2;
+ ------- + ------------------------------------ +
| @ p1 | @ p2 |
+ ------- + ------------------------------------ +
| 42S02 | 未知表'test.no_such_table'|
+ ------- + ------------------------------------ +

此扩展仅适用于当前诊断区域。 它不适用于第二个诊断区域,因为 GET STACKED DIAGNOSTICS 仅当当前上下文是条件处理程序时才允许。 如果不是这种情况, GET STACKED DIAGNOSTICS when handler not active 则会发生错误。

有关诊断区域的说明,请参见 第13.6.7.7节“MySQL诊断区域” 简而言之,它包含两种信息:

  • 语句信息,例如发生的条件数或受影响的行数。

  • 条件信息,例如错误代码和消息。 如果语句引发多个条件,则诊断区域的这一部分具有每个条件区域。 如果语句没有引发任何条件,则诊断区域的这一部分为空。

对于产生三个条件的语句,诊断区域包含语句和条件信息,如下所示:

声明信息:
  行数
  ......其他声明信息项......
条件区域列表:
  条件范围1:
    条件1的错误代码
    条件1的错误消息
    ......其他条件信息......
  条件区域2:
    条件2的错误代码:
    条件2的错误消息
    ......其他条件信息......
  条件范围3:
    条件3的错误代码
    条件3的错误消息
    ......其他条件信息......

GET DIAGNOSTICS 可以获取语句或条件信息,但不能同时在同一语句中获取:

  • 要获取语句信息,请将所需的语句项检索到目标变量中。 此实例 GET DIAGNOSTICS 将可用条件数和受行影响的计数分配给用户变量, @p1 并且 @p2

    获取诊断@ p1 = NUM​​BER,@ p2 = ROW_COUNT;
    
  • 要获取条件信息,请指定条件编号并将所需的条件项检索到目标变量中。 此实例 GET DIAGNOSTICS 将SQLSTATE值和错误消息分配给用户变量, @p3 并且 @p4

    获得诊断条件1
      @ p3 = RETURNED_SQLSTATE,@ p4 = MESSAGE_TEXT;
    

检索列表指定一个或多个 分配,以逗号分隔。 每个赋值都命名一个目标变量和一个 一个 指示符,具体取决于语句是否检索语句或条件信息。 target = item_name statement_information_item_name condition_information_item_name

target 用于存储项目信息的 有效 指示符可以是存储过程或函数参数,用其声明的存储的程序局部变量 DECLARE 或用户定义的变量。

有效的 condition_number 指示符可以是存储过程或函数参数,存储的程序本地变量 DECLARE ,用户定义的变量,系统变量或文字。 字符文字可以包括 _charset 介绍人。 如果条件编号不在1到具有信息的条件区域的数量范围内,则会发出警告。 在这种情况下,警告将添加到诊断区域而不清除它。

当条件发生时,MySQL不会填充所识别的所有条件项 GET DIAGNOSTICS 例如:

mysql> 
mysql>GET DIAGNOSTICS CONDITION 1
         @p5 = SCHEMA_NAME, @p6 = TABLE_NAME;SELECT @p5, @p6;
+ ------ + ------ +
| @ p5 | @ p6 |
+ ------ + ------ +
| | |
+ ------ + ------ +

在标准SQL中,如果有多个条件,则第一个条件与 SQLSTATE 前一个SQL语句返回 值相关。 在MySQL中,这不能保证。 要获得主要错误,您无法执行此操作:

获得诊断条件1 @errno = MYSQL_ERRNO;

相反,首先检索条件计数,然后使用它来指定要检查的条件数:

获取诊断@cno = NUM​​BER;
获得诊断条件@cno @errno = MYSQL_ERRNO;

有关允许的语句和条件信息项以及发生条件时填充的 信息的信息 ,请参阅“ 诊断区域信息项”

下面是一个示例,它使用 GET DIAGNOSTICS 存储过程上下文中的异常处理程序来评估插入操作的结果。 如果插入成功,则该过程用于 GET DIAGNOSTICS 获取受行影响的计数。 这表明 GET DIAGNOSTICS 只要尚未清除当前诊断区域 ,您就可以 多次 使用 来检索有关语句的信息。

CREATE PROCEDURE do_insert(值INT)
开始
  - 声明变量以保存诊断区域信息
  DECLARE代码CHAR(5)DEFAULT'00000';
  DECLARE msg TEXT;
  DECLARE行INT;
  DECLARE结果TEXT;
  - 为失败的插入声明异常处理程序
  DECLARE CONTINUE HANDLER用于SQLEXCEPTION
    开始
      获得诊断条件1
        code = RETURNED_SQLSTATE,msg = MESSAGE_TEXT;
    结束;

  - 执行插入
  INSERT INTO t1(int_col)VALUES(value);
  - 检查插入是否成功
  IF代码='00000'然后
    GET DIAGNOSTICS行= ROW_COUNT;
    SET result = CONCAT('insert succeeded,row count =',rows);
  其他
    SET result = CONCAT('insert failed,error =',code,',message =',msg);
  万一;
  - 说出发生了什么
  SELECT结果;
结束;

假设这 t1.int_col 是一个声明为的整数列 NOT NULL 在调用插入非 NULL NULL 值时, 该过程会产生这些结果

MySQL的> CALL do_insert(1);
+ --------------------------------- +
| 结果|
+ --------------------------------- +
| 插入成功,行计数= 1 |
+ --------------------------------- +

MySQL的> CALL do_insert(NULL);
+ ------------------------------------------------- ------------------------ +
| 结果|
+ ------------------------------------------------- ------------------------ +
| 插入失败,错误= 23000,消息=列'int_col'不能为空|
+ ------------------------------------------------- ------------------------ +

当条件处理程序激活时,会发生对诊断区域堆栈的推送:

  • 第一个(当前)诊断区域成为第二个(堆叠)诊断区域,并创建一个新的当前诊断区域作为其副本。

  • GET [CURRENT] DIAGNOSTICS 并且 GET STACKED DIAGNOSTICS 可以在处理程序中使用以访问当前和堆叠诊断区域的内容。

  • 最初,两个诊断区域都返回相同的结果,因此可以从当前诊断区域获取有关激活处理程序的条件的信息, 只要 在处理程序中不执行任何更改其当前诊断区域的语句即可。

  • 但是,在处理程序中执行的语句可以修改当前诊断区域,根据常规规则清除和设置其内容(请参阅 如何清除和填充诊断区域 )。

    获取有关处理程序激活条件的信息的更可靠方法是使用堆栈诊断区域,除了处理程序中执行的语句不能修改该区域 RESIGNAL 有关何时设置和清除当前诊断区域的信息,请参见 第13.6.7.7节“MySQL诊断区域”

下一个示例显示了如何 GET STACKED DIAGNOSTICS 在处理程序中使用 如何 获取有关已处理异常的信息,即使在当前诊断区域已被处理程序语句修改之后也是如此。

在存储过程中 p() ,我们尝试将两个值插入到包含 TEXT NOT NULL 的表中 第一个值是非 NULL 字符串,第二个值是 NULL 该列禁止 NULL 值,因此第一个插入成功但第二个插入导致异常。 该过程包括一个异常处理程序,用于映射尝试插入 NULL 空字符串的插入:

DROP TABLE IF EXISTS t1;
CREATE TABLE t1(c1 TEXT NOT NULL);
DROP程序如果存在p;
分隔符//
CREATE PROCEDURE p()
开始
  - 声明变量以保存诊断区域信息
  DECLARE errcount INT;
  DECLARE errno INT;
  DECLARE msg TEXT;
  DECLARE EXIT HANDLER用于SQLEXCEPTION
  开始
    - 这里当前的DA是非空的,因为没有先前的陈述
    - 在处理程序中执行已清除它
    获得当前的诊断条件1
      errno = MYSQL_ERRNO,msg = MESSAGE_TEXT;
    在映射插入之前选择'当前DA'AS op,errno,msg;
    获得堆叠的诊断条件1
      errno = MYSQL_ERRNO,msg = MESSAGE_TEXT;
    SELECT'在映射插入之前堆叠DA'AS op,errno,msg;

    - 映射尝试NULL插入到空字符串插入
    INSERT INTO t1(c1)VALUES('');

    - 这里当前DA应为空(如果INSERT成功),
    - 所以在尝试之前检查是否有条件
    - 获取条件信息
    获取当前诊断errcount = NUM​​BER;
    如果errcount = 0
    然后
      SELECT'映射插入成功,当前DA为空'AS op;
    其他
      获得当前的诊断条件1
        errno = MYSQL_ERRNO,msg = MESSAGE_TEXT;
      映射插入后选择'当前DA'AS op,errno,msg;
    万一 ;
    获得堆叠的诊断条件1
      errno = MYSQL_ERRNO,msg = MESSAGE_TEXT;
    在映射插入后选择'堆叠DA'AS op,errno,msg;
  结束;
  INSERT INTO t1(c1)VALUES('string 1');
  INSERT INTO t1(c1)VALUES(NULL);
结束;
//
分隔符;
CALL p();
SELECT * FROM t1;

处理程序激活时,当前诊断区域的副本将被推送到诊断区域堆栈。 处理程序首先显示当前和堆叠诊断区域的内容,这两个区域最初都是相同的:

+ --------------------------------- + ------- ------- + --------------------- +
| op | errno | 消息|
+ --------------------------------- + ------- ------- + --------------------- +
| 映射插入前的当前DA | 1048 | 列'c1'不能为空|
+ --------------------------------- + ------- ------- + --------------------- +

+ --------------------------------- + ------- ------- + --------------------- +
| op | errno | 消息|
+ --------------------------------- + ------- ------- + --------------------- +
| 在映射插入之前堆叠DA | 1048 | 列'c1'不能为空|
+ --------------------------------- + ------- ------- + --------------------- +

语句后执行的 GET DIAGNOSTICS 语句可能会重置当前诊断区域。 语句可能会重置当前的诊断区域。 例如,处理程序将 NULL 插入 映射 到空字符串插入并显示结果。 新插入成功并清除当前诊断区域,但堆栈诊断区域保持不变,并且仍包含有关激活处理程序的条件的信息:

+ ---------------------------------------------- +
| op |
+ ---------------------------------------------- +
| 映射插入成功,当前DA为空|
+ ---------------------------------------------- +

+ -------------------------------- + ------- -------- + -------------------- +
| op | errno | 消息|
+ -------------------------------- + ------- -------- + -------------------- +
| 映射插入后堆叠DA | 1048 | 列'c1'不能为空|
+ -------------------------------- + ------- -------- + -------------------- +

条件处理程序结束时,其当前诊断区域将从堆栈中弹出,堆叠的诊断区域将成为存储过程中的当前诊断区域。

该过程返回后,该表包含两行。 尝试插入 NULL 映射到空字符串插入 的空行产生

+ ---------- +
| c1 |
+ ---------- +
| string 1 |
| |
+ ---------- +

在前面的示例中, GET DIAGNOSTICS 条件处理程序中从当前和堆栈诊断区域检索信息 的前两个 语句返回相同的值。 如果重置当前诊断区域的语句在处理程序中较早执行,则情况不会出现这种情况。 假设 p() 重写它以将 DECLARE 语句放在处理程序定义中而不是在它之前:

CREATE PROCEDURE p()
开始
  DECLARE EXIT HANDLER用于SQLEXCEPTION
  开始
    - 声明变量以保存诊断区域信息
    DECLARE errcount INT;
    DECLARE errno INT;
    DECLARE msg TEXT;
    获得当前的诊断条件1
      errno = MYSQL_ERRNO,msg = MESSAGE_TEXT;
    在映射插入之前选择'当前DA'AS op,errno,msg;
    获得堆叠的诊断条件1
      errno = MYSQL_ERRNO,msg = MESSAGE_TEXT;
    SELECT'在映射插入之前堆叠DA'AS op,errno,msg;
...

在这种情况下,结果取决于版本:

  • 在MySQL 5.7.2之前, DECLARE 不会更改当前的诊断区域,因此前两个 GET DIAGNOSTICS 语句返回相同的结果,就像在原始版本中一样 p()

    在MySQL 5.7.2中,完成了一项工作,以确保所有非诊断语句按照SQL标准填充诊断区域。 DECLARE 是其中之一,所以在5.7.2及更高版本中, DECLARE 在处理程序开头执行的语句清除了当前的诊断区域和 GET DIAGNOSTICS 语句产生不同的结果:

    + --------------------------------- + ------- + ------ +
    | op | errno | 消息|
    + --------------------------------- + ------- + ------ +
    | 映射插入前的当前DA | NULL | NULL |
    + --------------------------------- + ------- + ------ +
    
    + --------------------------------- + ------- ------- + --------------------- +
    | op | errno | 消息|
    + --------------------------------- + ------- ------- + --------------------- +
    | 在映射插入之前堆叠DA | 1048 | 列'c1'不能为空|
    + --------------------------------- + ------- ------- + --------------------- +
    

要在获取有关激活处理程序的条件的信息时在条件处理程序中避免此问题,请确保访问堆栈诊断区域,而不是当前诊断区域。

13.6.7.4 RESIGNAL语法

RESIGNAL [ condition_value]
    [SET signal_information_item
    [,signal_information_item] ...]

condition_value:{
    SQLSTATE [VALUE] sqlstate_value
  |condition_name
}

signal_information_itemcondition_information_item_name=simple_value_specification

condition_information_item_name:{
    CLASS_ORIGIN
  | SUBCLASS_ORIGIN
  | MESSAGE_TEXT
  | MYSQL_ERRNO
  | CONSTRAINT_CATALOG
  | CONSTRAINT_SCHEMA
  | CONSTRAINT_NAME
  | CATALOG_NAME
  | SCHEMA_NAME
  | TABLE_NAME
  | COLUMN_NAME
  | CURSOR_NAME
}

condition_namesimple_value_specification
    (见下面的讨论)

RESIGNAL 传递在存储过程或函数,触发器或事件内的复合语句中执行条件处理程序期间可用的错误条件信息。 RESIGNAL 可能会在传递之前更改部分或全部信息。 RESIGNAL 有关 SIGNAL ,但,而不是发起条件的 SIGNAL 呢, RESIGNAL 继电器现有条件信息,有可能修改之后。

RESIGNAL 可以处理错误并返回错误信息。 否则,通过在处理程序中执行SQL语句,会导致导致处理程序激活的信息被破坏。 RESIGNAL 如果给定的处理程序可以处理部分情况,那么也可以使某些程序更短,然后将条件 上线 传递给另一个处理程序。

执行 RESIGNAL 语句 不需要任何特权

所有形式的 RESIGNAL 要求当前上下文是条件处理程序。 否则, RESIGNAL 是非法的并且发生 RESIGNAL when handler not active 错误。

要从诊断区域检索信息,请使用该 GET DIAGNOSTICS 语句(请参见 第13.6.7.3节“获取诊断语法” )。 有关诊断区域的信息,请参见 第13.6.7.7节“MySQL诊断区域”

RESIGNAL概述

对于 condition_value signal_information_item ,定义和规则是相同 RESIGNAL SIGNAL 例如, condition_value 可以是 SQLSTATE 值,值可以指示错误,警告或 未找到”。 有关其他信息,请参见 第13.6.7.5节”SIGNAL语法“

RESIGNAL 声明将 condition_value SET 这两个条款,是可选的。 这导致了几种可能的用途:

  • RESIGNAL 单独:

    RESIGNAL;
    
  • RESIGNAL 有了新的信号信息:

    RESIGNAL SET signal_information_item[,signal_information_item] ......;
    
  • RESIGNAL 具有条件值和可能的新信号信息:

    RESIGNAL condition_value
        [SET signal_information_item[,signal_information_item] ...];
    

这些用例都会导致诊断和条件区域发生变化:

  • 诊断区域包含一个或多个条件区域。

  • 条件区域包含条件信息项,例如 SQLSTATE MYSQL_ERRNO ,或 MESSAGE_TEXT

有一堆诊断区域。 当处理程序获得控制权时,它会将诊断区域推送到堆栈顶部,因此在处理程序执行期间有两个诊断区域:

  • 第一个(当前)诊断区域,作为最后一个诊断区域的副本启动,但将被处理程序中第一个更改当前诊断区域的语句覆盖。

  • 最后(堆叠)诊断区域,其具有在处理程序获得控制之前设置的条件区域。

诊断区域中条件区域的最大数量由 max_error_count 系统变量 的值确定 请参阅与 诊断区域相关的系统变量

仅限RESIGNAL

一个简单的 RESIGNAL 单独意味着 传递错误而不做任何改变。 它恢复了最后的诊断区域并使其成为当前的诊断区域。 也就是说,它 弹出 诊断区域堆栈。

在捕获条件的条件处理程序中, RESIGNAL 单独 使用 一个是执行一些其他操作,然后传递而不更改原始条件信息(在进入处理程序之前存在的信息)。

例:

DROP TABLE IF EXISTS xx;
分隔符//
CREATE PROCEDURE p()
开始
  DECLARE EXIT HANDLER用于SQLEXCEPTION
  开始
    SET @error_count = @error_count + 1;
    如果@a = 0那么RESIGNAL; 万一;
  结束;
  DROP TABLE xx;
结束//
分隔符;
SET @error_count = 0;
SET @a = 0;
CALL p();

假设 DROP TABLE xx 语句失败。 诊断区域堆栈如下所示:

DA 1. ERROR 1051(42S02):未知表'xx'

然后执行进入 EXIT 处理程序。 它首先将诊断区域推到堆栈顶部,现在看起来像这样:

DA 1. ERROR 1051(42S02):未知表'xx'
DA 2. ERROR 1051(42S02):未知表'xx'

此时,第一(当前)和第二(堆叠)诊断区域的内容是相同的。 可以通过在处理程序内随后执行的语句来修改第一诊断区域。

通常,过程语句会清除第一个诊断区域。 BEGIN 是一个例外,它不清楚,它什么都不做。 SET 它不是一个例外,它会清除,执行操作并产生 成功 的结果 诊断区域堆栈现在看起来像这样:

DA 1. ERROR 0000(00000):成功运行
DA 2. ERROR 1051(42S02):未知表'xx'

在这一点上,如果 @a = 0 RESIGNAL 弹出诊断区栈,它现在看起来是这样的:

DA 1. ERROR 1051(42S02):未知表'xx'

这就是呼叫者所看到的。

如果 @a 不为0,则处理程序简单地结束,这意味着当前诊断区域(已被 处理 不再使用 ,因此可以将其丢弃,从而使堆叠的诊断区域成为当前诊断区域再次。 诊断区域堆栈如下所示:

DA 1. ERROR 0000(00000):成功运行

细节使它看起来很复杂,但最终结果非常有用:处理程序可以执行而不会破坏有关导致处理程序激活的条件的信息。

RESIGNAL与新的信号信息

RESIGNAL 带有一个 SET 子句提供新的信号信息,因此该语句的意思是 通过更改传递错误

RESIGNAL SET signal_information_item[,signal_information_item] ......;

RESIGNAL 单独一样,想法是弹出诊断区域堆栈,以便原始信息熄灭。 RESIGNAL 单独 不同 SET 子句中 指定的任何内容都会 更改

例:

DROP TABLE IF EXISTS xx;
分隔符//
CREATE PROCEDURE p()
开始
  DECLARE EXIT HANDLER用于SQLEXCEPTION
  开始
    SET @error_count = @error_count + 1;
    IF @a = 0那么RESIGNAL SET MYSQL_ERRNO = 5; 万一;
  结束;
  DROP TABLE xx;
结束//
分隔符;
SET @error_count = 0;
SET @a = 0;
CALL p();

请记住,在前面的讨论中, RESIGNAL 单独导致诊断区域堆栈如下:

DA 1. ERROR 1051(42S02):未知表'xx'

RESIGNAL SET MYSQL_ERRNO = 5 语句导致此堆栈,这是调用者看到的:

DA 1.错误5(42S02):未知表'xx'

换句话说,它改变了错误号,而没有别的。

RESIGNAL 语句可以改变任何或所有信号信息项,使诊断区域的第一个条件区域看起来完全不同。

RESIGNAL具有条件值和可选的新信号信息

RESIGNAL 条件值表示 将条件推入当前诊断区域。 如果 SET 子句存在,它也会更改错误信息。

RESIGNAL condition_value
    [SET signal_information_item[,signal_information_item] ...];

这种形式可以 RESIGNAL 恢复最后的诊断区域并使其成为当前的诊断区域。 也就是说,它 弹出 诊断区域堆栈,这与 RESIGNAL 单独执行 简单 操作相同。 但是,它还会根据条件值或信号信息更改诊断区域。

例:

DROP TABLE IF EXISTS xx;
分隔符//
CREATE PROCEDURE p()
开始
  DECLARE EXIT HANDLER用于SQLEXCEPTION
  开始
    SET @error_count = @error_count + 1;
    如果@a = 0那么RESIGNAL SQLSTATE'45000'SET MYSQL_ERRNO = 5; 万一;
  结束;
  DROP TABLE xx;
结束//
分隔符;
SET @error_count = 0;
SET @a = 0;
SET @@ max_error_count = 2;
CALL p();
显示错误;

这与前面的示例类似,效果是相同的,除非 RESIGNAL 发生这种情况,当前条件区域在结尾处看起来不同。 (条件添加而不是替换现有条件的原因是使用条件值。)

RESIGNAL 语句包含条件值( SQLSTATE '45000' ),因此它添加了一个新的条件区域,从而产生如下所示的诊断区域堆栈:

DA 1.(条件2)ERROR 1051(42S02):未知表'xx'
      (条件1)错误5(45000)未知表'xx'

结果 CALL p() SHOW ERRORS 这个例子是:

MySQL的> CALL p();
错误5(45000):未知表'xx'
MySQL的> SHOW ERRORS;
+ ------- + ------ + ---------------------------------- +
| 等级| 代码| 消息|
+ ------- + ------ + ---------------------------------- +
| 错误| 1051 | 未知表'xx'|
| 错误| 5 | 未知表'xx'|
+ ------- + ------ + ---------------------------------- +
RESIGNAL需要条件处理程序上下文

所有形式的 RESIGNAL 要求当前上下文是条件处理程序。 否则, RESIGNAL 是非法的并且发生 RESIGNAL when handler not active 错误。 例如:

MySQL的> CREATE PROCEDURE p () RESIGNAL;
查询正常,0行受影响(0.00秒)

MySQL的> CALL p();
ERROR 1645(0K000):处理程序未激活时的RESIGNAL

这是一个更难的例子:

分隔符//
创建功能f()返回INT
开始
  RESIGNAL;
  返回5;
结束//
CREATE PROCEDURE p()
开始
  DECLARE EXIT HANDLER for SQLEXCEPTION SET @ a = f();
  SIGNAL SQLSTATE'55555';
结束//
分隔符;
CALL p();

RESIGNAL 发生在存储的函数中 f() 虽然 f() 它本身是在 EXIT 处理程序 的上下文中调用的 ,但是其中的执行 f() 具有自己的上下文,而不是处理程序上下文。 因此, RESIGNAL f() 中一个结果 处理程序不活跃 的错误。

13.6.7.5 SIGNAL语法

SIGNAL condition_value
    [SET signal_information_item
    [,signal_information_item] ...]

condition_value:{
    SQLSTATE [VALUE] sqlstate_value
  |condition_name
}

signal_information_itemcondition_information_item_name=simple_value_specification

condition_information_item_name:{
    CLASS_ORIGIN
  | SUBCLASS_ORIGIN
  | MESSAGE_TEXT
  | MYSQL_ERRNO
  | CONSTRAINT_CATALOG
  | CONSTRAINT_SCHEMA
  | CONSTRAINT_NAME
  | CATALOG_NAME
  | SCHEMA_NAME
  | TABLE_NAME
  | COLUMN_NAME
  | CURSOR_NAME
}

condition_namesimple_value_specification
    (见下面的讨论)

SIGNAL 返回 错误的方法。 SIGNAL 向处理程序,应用程序的外部部分或客户端提供错误信息。 此外,它还可以控制错误的特征(错误号, SQLSTATE 值,消息)。 如果没有 SIGNAL ,则必须采用诸如故意引用不存在的表之类的变通方法来导致例程返回错误。

执行 SIGNAL 语句 不需要任何特权

要从诊断区域检索信息,请使用该 GET DIAGNOSTICS 语句(请参见 第13.6.7.3节“获取诊断语法” )。 有关诊断区域的信息,请参见 第13.6.7.7节“MySQL诊断区域”

信号概述

condition_value 一个 SIGNAL 声明中表示要返回错误值。 它可以是一个 SQLSTATE 值(一个5个字符的字符串文字)或一个 condition_name 引用之前定义的命名条件 DECLARE ... CONDITION (参见 第13.6.7.1节“DECLARE ... CONDITION语法”) )。

一个 SQLSTATE 值可以指示错误,警告或 未找到。 “值 的前两个字符表示其错误类,如 信号条件信息项中所述 某些信号值导致语句终止; 请参阅 信号对处理程序,游标和语句的影响

语句 SQLSTATE SIGNAL 不应该以, '00' 因为这些值表示成功,并且对于发出错误信号无效。 无论 SQLSTATE 是直接在 SIGNAL 语句中还是在语句中引用的命名条件中 指定值, 都是如此 如果该值无效, Bad SQLSTATE 则会发生错误。

为了用信号的通用 SQLSTATE 值,使用 '45000' ,这意味着 未处理用户定义的异常。

SIGNAL 语句可选地包括一个 SET 子句, 子句包含多个信号项,在 condition_information_item_name = simple_value_specification 赋值 列表中 ,以逗号分隔。

每个 条款中 condition_information_item_name 只能指定一次 SET 否则, Duplicate condition information item 会发生错误。

simple_value_specification 可以使用存储过程或函数参数,声明的存储程序局部变量 DECLARE ,用户定义变量,系统变量或文字 来指定 有效的 指示符 字符文字可以包括 _charset 介绍人。

有关允许 condition_information_item_name 值的 信息 ,请参阅 信号条件信息项

以下过程根据 pval 其输入参数 的值发出错误或警告信号

CREATE PROCEDURE p(pval INT)
开始
  DECLARE SQLSTATE'45000'的专业条件;
  如果pval = 0那么
    SIGNAL SQLSTATE'01000';
  ELSEIF pval = 1那么
    SIGNAL SQLSTATE'45000'
      SET MESSAGE_TEXT ='发生错误';
  ELSEIF pval = 2那么
    SIGNAL专业
      SET MESSAGE_TEXT ='发生错误';
  其他
    SIGNAL SQLSTATE'01000'
      SET MESSAGE_TEXT ='发生警告',MYSQL_ERRNO = 1000;
    SIGNAL SQLSTATE'45000'
      SET MESSAGE_TEXT ='发生错误',MYSQL_ERRNO = 1001;
  万一;
结束;

如果 pval 为0,则 p() 发出警告,因为以 SQLSTATE 值开头的值是 '01' 警告类中的信号。 警告不会终止该过程,并且可以 SHOW WARNINGS 在过程返回后 看到

如果 pval 为1,则 p() 表示错误并设置 MESSAGE_TEXT 条件信息项。 该错误终止该过程,并返回带有错误信息的文本。

如果 pval 为2,则发出相同的错误信号,尽管 SQLSTATE 在这种情况下使用命名条件指定值。

如果 pval 是其他任何内容,请 p() 首先发出警告并设置消息文本和错误编号条件信息项。 此警告不会终止该过程,因此继续执行 p() 然后发出错误信号。 该错误会终止该过程。 警告设置的消息文本和错误编号将替换为错误设置的值,这些值随错误信息一起返回。

SIGNAL 通常在存储的程序中使用,但它是一个MySQL扩展,它允许在处理程序上下文之外。 例如,如果调用 mysql 客户端程序,则可以在提示符处输入以下任何语句:

SIGNAL SQLSTATE'77777';

在插入之前创建触发器t_bi
  对于每个行信号SQLSTATE'777777';

创造活动e每周一次安排
  DO SIGNAL SQLSTATE'777777';

SIGNAL 根据以下规则执行:

如果 SIGNAL 语句指示特定 SQLSTATE 值,则该值用于表示指定的条件。 例:

CREATE PROCEDURE p(除数INT)
开始
  IF divisor = 0那么
    SIGNAL SQLSTATE'22012';
  万一;
结束;

如果 SIGNAL 语句使用命名条件,则必须在适用于该 SIGNAL 语句的 某个范围中声明该条件 ,并且必须使用 SQLSTATE 值而不是MySQL错误号 来定义该条件 例:

CREATE PROCEDURE p(除数INT)
开始
  DECLARE divide_by_zero CONDITION FOR SQLSTATE'22012';
  IF divisor = 0那么
    SIGNAL divide_by_zero;
  万一;
结束;

如果在 SIGNAL 语句 范围内不存在命名条件 Undefined CONDITION 则会发生错误。

如果 SIGNAL 引用使用MySQL错误号而不是 SQLSTATE 定义的命名条件, SIGNAL/RESIGNAL can only use a CONDITION defined with SQLSTATE 则会发生错误。 以下语句导致该错误,因为命名条件与MySQL错误号相关联:

DECLARE no_such_table 1051条件;
SIGNAL no_such_table;

如果具有给定名称的条件在不同范围内多次声明,则应用具有最大本地范围的声明。 请考虑以下过程:

CREATE PROCEDURE p(除数INT)
开始
  为SQLSTATE'45000'声明my_error条件;
  IF divisor = 0那么
    开始
      为SQLSTATE'22012'声明my_error条件;
      SIGNAL my_error;
    结束;
  万一;
  SIGNAL my_error;
结束;

如果 divisor 为0,则 SIGNAL 执行 第一个 语句。 提出最内层的 my_error 条件声明 SQLSTATE '22012'

如果 divisor 不为0,则 SIGNAL 执行 第二个 语句。 提出最外面的 my_error 条件声明 SQLSTATE '45000'

有关服务器在发生条件时如何选择处理程序的信息,请参见 第13.6.7.6节“处理程序的范围规则”

可以在异常处理程序中引发信号:

CREATE PROCEDURE p()
开始
  DECLARE EXIT HANDLER用于SQLEXCEPTION
  开始
    SIGNAL SQLSTATE VALUE'999999'
      SET MESSAGE_TEXT ='发生错误';
  结束;
  DROP TABLE no_such_table;
结束;

CALL p() 到达 DROP TABLE 声明。 没有命名的表 no_such_table ,因此激活了错误处理程序。 错误处理程序破坏原始错误( 没有这样的表 )并使用 SQLSTATE '99999' 和消息 产生新错误 An error occurred

信号条件信息项

下表列出了可以在 SIGNAL (或 RESIGNAL )语句中 设置的诊断区域条件信息项的名称 所有项目都是标准SQL,但 MYSQL_ERRNO 它是MySQL扩展。 有关这些项的更多信息,请参见 第13.6.7.7节“MySQL诊断区”

项目名称定义
--------- ----------
CLASS_ORIGIN VARCHAR(64)
SUBCLASS_ORIGIN VARCHAR(64)
CONSTRAINT_CATALOG VARCHAR(64)
CONSTRAINT_SCHEMA VARCHAR(64)
CONSTRAINT_NAME VARCHAR(64)
CATALOG_NAME VARCHAR(64)
SCHEMA_NAME VARCHAR(64)
TABLE_NAME VARCHAR(64)
COLUMN_NAME VARCHAR(64)
CURSOR_NAME VARCHAR(64)
MESSAGE_TEXT VARCHAR(128)
MYSQL_ERRNO SMALLINT UNSIGNED

字符项的字符集是UTF-8。

NULL SIGNAL 语句中 分配 条件信息项 是非法的

SIGNAL 语句总是指定一个 SQLSTATE 值,或者直接地或间接地通过参照具有一个定义的命名条件 SQLSTATE 值。 值的前两个字符 SQLSTATE 是其类,类确定条件信息项的默认值:

  • 等级= '00' (成功)

    非法。 SQLSTATE 以...开头的值 '00' 表示成功且无效 SIGNAL

  • 等级= '01' (警告)

    MESSAGE_TEXT ='未处理的用户定义警告条件';
    MYSQL_ERRNO = ER_SIGNAL_WARN
    
  • 等级= '02' (未找到)

    MESSAGE_TEXT ='未处理的用户定义的未找到条件';
    MYSQL_ERRNO = ER_SIGNAL_NOT_FOUND
    
  • 班级> '02' (例外)

    MESSAGE_TEXT ='未处理的用户定义的异常条件';
    MYSQL_ERRNO = ER_SIGNAL_EXCEPTION
    

对于合法类,其他条件信息项设置如下:

CLASS_ORIGIN = SUBCLASS_ORIGIN ='';
CONSTRAINT_CATALOG = CONSTRAINT_SCHEMA = CONSTRAINT_NAME ='';
CATALOG_NAME = SCHEMA_NAME = TABLE_NAME = COLUMN_NAME ='';
CURSOR_NAME ='';

SIGNAL 执行 后可访问的错误值是 语句和 SQLSTATE 引发 这些值可从C API获得: SIGNAL MESSAGE_TEXT MYSQL_ERRNO

在SQL级别,输出来自 SHOW WARNINGS SHOW ERRORS 指示 列中的 MYSQL_ERRNO MESSAGE_TEXT Code Message

要从诊断区域检索信息,请使用该 GET DIAGNOSTICS 语句(请参见 第13.6.7.3节“获取诊断语法” )。 有关诊断区域的信息,请参见 第13.6.7.7节“MySQL诊断区域”

信号对处理程序,游标和语句的影响

根据信号类,信号对语句执行有不同的影响。 该类确定错误的严重程度。 MySQL忽略 sql_mode 系统变量 的值 ; 特别是严格的SQL模式并不重要。 MySQL也忽略了 IGNORE :意图 SIGNAL 是明确地引发用户生成的错误,因此永远不会忽略信号。

在以下描述中, 未处理 表示没有 SQLSTATE 定义 信号 值的 处理程序 DECLARE ... HANDLER

  • 等级= '00' (成功)

    非法。 SQLSTATE 以...开头的值 '00' 表示成功且无效 SIGNAL

  • 等级= '01' (警告)

    warning_count 系统变量 的值 上升。 SHOW WARNINGS 显示信号。 SQLWARNING 处理程序捕获信号。

    无法从存储的函数返回警告,因为 RETURN 导致函数返回 语句将清除诊断区域。 因此,该声明清除了可能存在的任何警告(并重置 warning_count 为0)。

  • 等级= '02' (未找到)

    NOT FOUND 处理程序捕获信号。 游标没有任何影响。 如果信号在存储函数中未处理,则语句结束。

  • 班级> '02' (例外)

    SQLEXCEPTION 处理程序捕获信号。 如果信号在存储函数中未处理,则语句结束。

  • 等级= '40'

    被视为普通例外。

13.6.7.6处理程序的范围规则

存储的程序可以包括当在程序内发生某些条件时要调用的处理程序。 每个处理程序的适用性取决于它在程序定义中的位置以及它处理的条件或条件:

  • 在声明的处理程序 BEGIN ... END 块的范围只为以下的块中的处理程序声明的SQL语句。 如果处理程序本身引发了一个条件,它就无法处理该条件,也无法在块中声明任何其他处理程序。 在以下示例中,处理程序 H1 H2 在范围为通过发言中提出的条件 stmt1 stmt2 但无论是 H1 也不 H2 在范围上,以在体内引发条件 H1 H2

    开始 - 外块
      DECLARE EXIT HANDLER for ...;  - 处理程序H1
      DECLARE EXIT HANDLER for ...;  - 处理程序H2
      stmt1;
      stmt2;
    结束;
    
  • 处理程序仅在声明它的块的范围内,并且对于在该块之外发生的条件不能被激活。 在以下示例中,handler H1 stmt1 内部块的 范围 内,但不在 stmt2 外部块中:

    开始 - 外块
      开始 - 内部块
        DECLARE EXIT HANDLER for ...;  - 处理程序H1
        stmt1;
      结束;
      stmt2;
    结束;
    
  • 处理程序可以是特定的或一般的。 特定处理程序用于MySQL错误代码, SQLSTATE 值或条件名称。 一般的处理程序是用于在一个状态 SQLWARNING SQLEXCEPTION NOT FOUND 类。 条件特异性与条件优先级相关,如稍后所述。

可以在不同的范围和不同的特性声明多个处理程序。 例如,外部块中可能存在特定的MySQL错误代码处理程序,而 SQLWARNING 内部块中可能 存在常规 处理程序。 或者可能存在特定MySQL错误代码和 SQLWARNING 同一块中 的通用 类的 处理程序

是否激活处理程序不仅取决于其自身的范围和条件值,还取决于其他处理程序的存在。 当存储的程序中出现条件时,服务器在当前范围(当前 BEGIN ... END 块)中 搜索适用的处理程序 如果没有适用的处理程序,则在每个连续的包含范围(块)中使用处理程序向外继续搜索。 当服务器在给定范围内找到一个或多个适用的处理程序时,它会根据条件优先级在其中选择:

  • MySQL错误代码处理程序优先于 SQLSTATE 值处理程序。

  • 一个 SQLSTATE 值处理程序优先于一般 SQLWARNING SQLEXCEPTION NOT FOUND 处理程序。

  • 一个 SQLEXCEPTION 处理程序优先于 SQLWARNING 处理程序。

  • 可以有几个具有相同优先级的适用处理程序。 例如,语句可以生成具有不同错误代码的多个警告,对于每个错误代码,存在特定于错误的处理程序。 在这种情况下,服务器激活哪个处理程序的选择是不确定的,并且可能根据条件发生的环境而改变。

处理程序选择规则的一个含义是,如果多个适用的处理程序出现在不同的作用域中,则具有最多本地作用域的处理程序优先于外部作用域中的处理程序,甚至优先于更具体条件的处理程序。

如果条件发生时没有适当的处理程序,则采取的操作取决于条件的类:

  • 对于 SQLEXCEPTION 条件,存储的程序终止于引发条件的语句,就像有一个 EXIT 处理程序一样。 如果程序被另一个存储程序调用,则调用程序使用应用于其自己的处理程序的处理程序选择规则来处理该条件。

  • 对于 SQLWARNING 条件,程序继续执行,就像有一个 CONTINUE 处理程序一样。

  • 对于 NOT FOUND 条件,如果条件正常提升,则动作是 CONTINUE 如果是由 SIGNAL or 提出的 RESIGNAL ,那么行动就是 EXIT

以下示例演示了MySQL如何应用处理程序选择规则。

此过程包含两个处理程序,一个用于 尝试删除不存在的表时发生 的特定 SQLSTATE 值( '42S02' ),另一个用于常规 SQLEXCEPTION 类:

CREATE PROCEDURE p1()
开始
  为SQLSTATE'42S02'声明继续HANDLER
    SELECT'SQLSTATE处理程序已激活'AS msg;
  DECLARE CONTINUE HANDLER用于SQLEXCEPTION
    SELECT'SQLEXCEPTION处理程序已激活'AS msg;

  DROP TABLE test.t;
结束;

两个处理程序都在同一个块中声明,并具有相同的范围。 但是, SQLSTATE 处理程序优先于 SQLEXCEPTION 处理程序,因此如果表 t 不存在,则该 DROP TABLE 语句会引发一个激活 SQLSTATE 处理程序 的条件

MySQL的> CALL p1();
+ -------------------------------- +
| 消息|
+ -------------------------------- +
| SQLSTATE处理程序已激活|
+ -------------------------------- +

此过程包含相同的两个处理程序。 但这次, DROP TABLE 语句和 SQLEXCEPTION 处理程序位于相对于 SQLSTATE 处理程序 的内部块中

CREATE PROCEDURE p2()
开始 - 外块
    为SQLSTATE'42S02'声明继续HANDLER
      SELECT'SQLSTATE处理程序已激活'AS msg;
  开始 - 内部块
    DECLARE CONTINUE HANDLER用于SQLEXCEPTION
      SELECT'SQLEXCEPTION处理程序已激活'AS msg;

    DROP TABLE test.t;  - 发生在内部区块内
  结束;
结束;

在这种情况下,更符合条件发生位置的处理程序优先。 SQLEXCEPTION 处理器激活,即使它是不是更一般的 SQLSTATE 处理程序:

MySQL的> CALL p2();
+ ------------------------------------ +
| 消息|
+ ------------------------------------ +
| SQLEXCEPTION处理程序已激活|
+ ------------------------------------ +

在此过程中,其中一个处理程序在 DROP TABLE 语句 范围内的块中 声明:

CREATE PROCEDURE p3()
开始 - 外块
  DECLARE CONTINUE HANDLER用于SQLEXCEPTION
    SELECT'SQLEXCEPTION处理程序已激活'AS msg;
  开始 - 内部块
    为SQLSTATE'42S02'声明继续HANDLER
      SELECT'SQLSTATE处理程序已激活'AS msg;
  结束;

  DROP TABLE test.t;  - 发生在外部区块内
结束;

只有 SQLEXCEPTION 处理程序适用,因为另一个处理程序不在由以下内容引发的条件的范围内 DROP TABLE

MySQL的> CALL p3();
+ ------------------------------------ +
| 消息|
+ ------------------------------------ +
| SQLEXCEPTION处理程序已激活|
+ ------------------------------------ +

在此过程中,两个处理程序都在 DROP TABLE 语句 范围内的块中 声明:

CREATE PROCEDURE p4()
开始 - 外块
  开始 - 内部块
    DECLARE CONTINUE HANDLER用于SQLEXCEPTION
      SELECT'SQLEXCEPTION处理程序已激活'AS msg;
    为SQLSTATE'42S02'声明继续HANDLER
      SELECT'SQLSTATE处理程序已激活'AS msg;
  结束;

  DROP TABLE test.t;  - 发生在外部区块内
结束;

处理程序都不适用,因为它们不在范围内 DROP TABLE 语句引发的条件未处理,并以错误终止该过程:

MySQL的> CALL p4();
ERROR 1051(42S02):未知表'test.t'

13.6.7.7 MySQL诊断区域

SQL语句生成填充诊断区域的诊断信息。 标准SQL具有诊断区域堆栈,其中包含每个嵌套执行上下文的诊断区域。 标准SQL还支持 GET STACKED DIAGNOSTICS 在条件处理程序执行期间引用第二个诊断区域的语法。

以下讨论描述了MySQL中诊断区域的结构,MySQL识别的信息项,清除语句和设置诊断区域的方式,以及诊断区域如何从堆栈中推送和弹出。

诊断区域结构

诊断区域包含两种信息:

  • 语句信息,例如发生的条件数或受影响的行数。

  • 条件信息,例如错误代码和消息。 如果语句引发多个条件,则诊断区域的这一部分具有每个条件区域。 如果语句没有引发任何条件,则诊断区域的这一部分为空。

对于产生三个条件的语句,诊断区域包含语句和条件信息,如下所示:

声明信息:
  行数
  ......其他声明信息项......
条件区域列表:
  条件范围1:
    条件1的错误代码
    条件1的错误消息
    ......其他条件信息......
  条件区域2:
    条件2的错误代码:
    条件2的错误消息
    ......其他条件信息......
  条件范围3:
    条件3的错误代码
    条件3的错误消息
    ......其他条件信息......
诊断区域信息项

诊断区域包含语句和条件信息项。 数字项是整数。 字符项的字符集是UTF-8。 没有项目可以 NULL 如果填充诊断区域的语句未设置语句或条件项,则其值为0或空字符串,具体取决于项数据类型。

诊断区域的语句信息部分包含以下项目:

  • NUMBER :一个整数,指示包含信息的条件区域的数量。

  • ROW_COUNT :一个整数,指示受语句影响的行数。 ROW_COUNT 具有与 ROW_COUNT() 函数 相同的值 (请参见 第12.15节“信息函数” )。

诊断区域的条件信息部分包含每个条件的条件区域。 条件区域从1到 NUMBER 语句条件项 的值编号 如果 NUMBER 为0,则没有条件区域。

每个条件区域都包含以下列表中的项目。 所有项目都是标准SQL,但 MYSQL_ERRNO 它是MySQL扩展。 这些定义适用于除信号之外产生的条件(即通过 SIGNAL RESIGNAL 声明)。 对于非信号条件,MySQL仅填充那些未描述为始终为空的条件项。 信号对条件区域的影响将在后面描述。

  • CLASS_ORIGIN :包含 RETURNED_SQLSTATE 类的字符串 如果 RETURNED_SQLSTATE 值以SQL标准文档ISO 9075-2(第24.1节,SQLSTATE)中定义的类值开头, CLASS_ORIGIN 则为 'ISO 9075' 否则 CLASS_ORIGIN 就是 'MySQL'

  • SUBCLASS_ORIGIN :包含 RETURNED_SQLSTATE 的子类的字符串 如果 CLASS_ORIGIN 'ISO 9075' RETURNED_SQLSTATE 结束 '000' SUBCLASS_ORIGIN 'ISO 9075' 否则 SUBCLASS_ORIGIN 就是 'MySQL'

  • RETURNED_SQLSTATE :一个字符串,指示 SQLSTATE 条件 值。

  • MESSAGE_TEXT :一个字符串,指示条件的错误消息。

  • MYSQL_ERRNO :一个整数,指示条件的MySQL错误代码。

  • CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME :字符串指示目录,架构,并将其命名为违反约束。 他们总是空着的。

  • CATALOG_NAME SCHEMA_NAME TABLE_NAME COLUMN_NAME :字符串指示目录,架构,表和相关的状态栏。 他们总是空着的。

  • CURSOR_NAME :一个表示游标名称的字符串。 这总是空的。

对于 RETURNED_SQLSTATE MESSAGE_TEXT 以及 MYSQL_ERRNO 特定的错误值,请参见 第B.3.1节,“服务器错误信息参考”

如果 SIGNAL (或 RESIGNAL )语句填充诊断区域,则其 SET 子句可以分配给任何条件信息项,除了 RETURNED_SQLSTATE 对项数据类型合法的任何值。 SIGNAL 也设置 RETURNED_SQLSTATE 值,但不直接在其 SET 子句中。 该值来自 SIGNAL 语句 SQLSTATE 参数。

SIGNAL 还设置了声明信息项。 它设置 NUMBER 为1. ROW_COUNT 错误 设置 为-1,否则 设置 为0。

如何清除和填充诊断区域

非诊断SQL语句自动填充诊断区域,其内容可以使用 SIGNAL RESIGNAL 语句 显式设置 可以检查诊断区域 GET DIAGNOSTICS 以提取特定项目,或者使用 SHOW WARNINGS SHOW ERRORS 查看条件或错误。

SQL语句清除并设置诊断区域如下:

  • 当服务器在解析后开始执行语句时,它会清除非诊断语句的诊断区域。 诊断语句不会清除诊断区域。 这些陈述是诊断性的:

  • 如果语句引发某个条件,则会清除诊断区域中属于早期语句的条件。 例外情况是由 诊断区域 引发的条件 GET DIAGNOSTICS RESIGNAL 添加到诊断区域而不清除它。

因此,即使在开始执行时通常不会清除诊断区域的语句也会在语句引发条件时清除它。

以下示例显示了各种语句对诊断区域的影响, SHOW WARNINGS 用于显示有关存储在那里的条件的信息。

DROP TABLE 语句清除诊断区域并在条件发生时填充它:

MySQL的> DROP TABLE IF EXISTS test.no_such_table;
查询正常,0行受影响,1警告(0.01秒)

MySQL的> SHOW WARNINGS;
+ ------- + ------ + ---------------------------------- -  +
| 等级| 代码| 消息|
+ ------- + ------ + ---------------------------------- -  +
| 注意| 1051 | 未知表'test.no_such_table'|
+ ------- + ------ + ---------------------------------- -  +
1排(0.00秒)

SET 语句生成错误,因此它会清除并填充诊断区域:

MySQL的> SET @x = @@x;
ERROR 1193(HY000):未知的系统变量'x'

MySQL的> SHOW WARNINGS;
+ ------- + ------ + ----------------------------- +
| 等级| 代码| 消息|
+ ------- + ------ + ----------------------------- +
| 错误| 1193 | 未知的系统变量'x'|
+ ------- + ------ + ----------------------------- +
1排(0.00秒)

前面的 SET 语句产生了一个条件,因此1是此时唯一有效的条件数 GET DIAGNOSTICS 以下语句使用条件号2,它会生成一个警告,该警告将添加到诊断区域而不清除它:

MySQL的> GET DIAGNOSTICS CONDITION 2 @p = MESSAGE_TEXT;
查询正常,0行受影响,1警告(0.00秒)

MySQL的> SHOW WARNINGS;
+ ------- + ------ + + ------------------------------
| 等级| 代码| 消息|
+ ------- + ------ + + ------------------------------
| 错误| 1193 | 未知的系统变量'xx'|
| 错误| 1753年| 条件号无效|
+ ------- + ------ + + ------------------------------
2行(0.00秒)

现在诊断区域中有两个条件,因此相同的 GET DIAGNOSTICS 语句成功:

MySQL的> GET DIAGNOSTICS CONDITION 2 @p = MESSAGE_TEXT;
查询正常,0行受影响(0.00秒)

MySQL的> SELECT @p;
+ -------------------------- +
| @p |
+ -------------------------- +
| 条件号无效|
+ -------------------------- +
1排(0.01秒)
诊断区域堆栈的工作原理

当推送到诊断区域堆栈时,第一个(当前)诊断区域成为第二个(堆叠)诊断区域,并创建一个新的当前诊断区域作为其副本。 在以下情况下,诊断区域将被推入并从堆栈中弹出:

  • 执行存储的程序

    在程序执行之前发生推送,之后发生弹出。 如果存储的程序在处理程序执行时结束,则可以弹出多个诊断区域; 这是由于没有适当的处理程序或由于处理程序中的异常而发生 RETURN 的。

    然后,弹出的诊断区域中的任何警告或错误条件都会添加到当前诊断区域,但对于触发器,仅添加错误。 当存储的程序结束时,调用者在其当前的对角线区域中看到这些条件。

  • 在存储的程序中执行条件处理程序

    当由于条件处理程序激活而发生推送时,堆叠的诊断区域是在推送之前存储的程序中当前的区域。 新的当前诊断区域是处理程序的当前诊断区域。 GET [CURRENT] DIAGNOSTICS 并且 GET STACKED DIAGNOSTICS 可以在处理程序中使用以访问当前(处理程序)和堆栈(存储程序)诊断区域的内容。 最初,它们返回相同的结果,但在处理程序中执行的语句会修改当前诊断区域,根据常规规则清除和设置其内容(请参阅 如何清除和填充诊断区域) )。 除了处理程序中执行的语句之外,不能修改堆叠的诊断区域 RESIGNAL

    如果处理程序成功执行,则弹出当前(处理程序)诊断区域,堆叠(存储程序)诊断区域再次成为当前诊断区域。 在处理程序执行期间添加到处理程序诊断区域的条件将添加到当前诊断区域。

  • 执行 RESIGNAL

    RESIGNAL 语句传递在存储程序内的复合语句中执行条件处理程序期间可用的错误条件信息。 RESIGNAL 可能会在传递之前更改部分或全部信息,修改诊断堆栈,如 第13.6.7.4节“RESIGNAL语法”中所述

与诊断区域相关的系统变量

某些系统变量控制或与诊断区域的某些方面相关:

  • max_error_count 控制诊断区域中的条件区域数量。 如果出现的情况多于此情况,MySQL会默默地丢弃超出条件的信息。 (添加的条件 RESIGNAL 总是被添加,必要时会丢弃较旧的条件以腾出空间。)

  • warning_count 表示发生的条件数。 这包括错误,警告和注释。 通常, NUMBER 并且 warning_count 是相同的。 但是,随着产生的条件数量的增加 max_error_count ,值 warning_count 继续上升,但 NUMBER 仍保持上限, max_error_count 因为诊断区域中没有存储其他条件。

  • error_count 表示发生的错误数。 此值包括 未找到 和例外情况,但不包括警告和注释。 就像 warning_count ,它的价值可以超过 max_error_count

  • 如果 sql_notes 系统变量设置为0,则不会存储注释,也不会增加注释 warning_count

示例:如果 max_error_count 为10,则诊断区域最多可包含10个条件区域。 假设一个语句提出了20个条件,其中12个是错误。 在这种情况下,诊断区域包含前10个条件, NUMBER 即10, warning_count 是20,并且 error_count 是12。

max_error_count 在下次尝试修改诊断区域之前 ,对值的更改 无效。 如果诊断区域包含10个条件区域并且 max_error_count 设置为5,则不会立即影响诊断区域的大小或内容。

13.6.7.8条件处理和OUT或INOUT参数

如果存储过程以未处理的异常退出,则修改后的值 OUT INOUT 参数不会传回给调用者。

如果一个异常是由处理 CONTINUE EXIT 包含处理程序 RESIGNAL 语句,执行 RESIGNAL 持久性有机污染物的诊断区域叠加,从而信号异常(即进入处理程序之前存在的信息)。 如果异常是错误,则 OUT 值的 INOUT 参数不会传回给调用者。

13.7数据库管理声明

13.7.1账户管理声明

MySQL帐户信息存储在 mysql 系统数据库 的表中 该数据库和访问控制系统将在 第5章 MySQL服务器管理中 进行详细讨论 ,您应该参考其中了解更多详细信息。

重要

一些MySQL版本引入了对授权表的更改以添加新的特权或功能。 要确保您可以利用任何新功能,请在升级MySQL时将授权表更新为当前结构。 请参见 第2.11节“升级MySQL”

read_only 启用了系统变量,账户管理语句需要 CONNECTION_ADMIN SUPER 特权,除了所需的其他特权。 这是因为它们修改了 mysql 系统数据库中的

帐户管理语句具有原子性和崩溃安全性。 有关更多信息,请参见 第13.1.1节“原子数据定义语句支持”

13.7.1.1 ALTER USER语法

ALTER USER [IF EXISTS]
     user[ auth_option] [,user[ auth_option]] ......
    [要求{无|] tls_option[[AND] tls_option] ...}]
    [WITH resource_option[ resource_option] ...]
    [ password_option| lock_option] ......

ALTER USER [IF EXISTS] USER() user_func_auth_option

更改用户[如果存在]
    user 默认角色
    {无| 所有| role[,role] ......}

user
    (参见第6.2.4节“指定帐户名”

auth_option:{
    由' auth_string' 识别
        [REPLACE' current_auth_string']
        [保留当前密码]
  | auth_plugin
  |来识别 通过auth_plugin' auth_string'确认
        [REPLACE' current_auth_string']
        [保留当前密码]
  | auth_plugin' auth_string''确认
  | 丢掉旧密码
}

user_func_auth_option:{
    由' auth_string' 识别
        [REPLACE' current_auth_string']
        [保留当前密码]
  | 丢掉旧密码
}

tls_option:{
   SSL
 | X509
 | CIPHER' cipher'
 | 发行人' issuer'
 | 主题' subject'
}

resource_option:{
    MAX_QUERIES_PER_HOUR count
  | MAX_UPDATES_PER_HOUR count
  | MAX_CONNECTIONS_PER_HOUR count
  | MAX_USER_CONNECTIONScount
}

password_option:{
    PASSWORD EXPIRE [默认值] 永远不会 间隔日N]
  | 密码历史{默认| N}
  | PASSWORD REUSE INTERVAL {默认| N天}
  | 密码要求当前[默认值] 可选的]
}

lock_option:{
    账户锁
  | 帐户解锁
}

ALTER USER 语句修改了MySQL帐户。 它可以为现有帐户修改身份验证,角色,SSL / TLS,资源限制和密码管理属性。 它还可用于锁定和解锁帐户。

在大多数情况下, ALTER USER 需要全局 CREATE USER 特权或 系统数据库 UPDATE 特权 mysql 例外情况是:

  • 使用非匿名帐户连接到服务器的任何客户端都可以更改该帐户的密码。 (特别是,您可以更改自己的密码。)要查看服务器对您进行身份验证的帐户,请调用以下 CURRENT_USER() 函数:

    SELECT CURRENT_USER();
    
  • 对于 DEFAULT ROLE 语法, ALTER USER 需要以下权限:

    • 为其他用户设置默认角色需要全局 CREATE USER 权限或 系统表 UPDATE 权限 mysql.default_roles

    • 为自己设置默认角色不需要特殊权限,只要您希望将您想要的角色授予您。

  • 修改辅助密码的语句需要以下权限:

    • APPLICATION_PASSWORD_ADMIN 权限才能使用 RETAIN CURRENT PASSWORD DISCARD OLD PASSWORD 子句 ALTER USER 应用到自己的帐户报表。 由于大多数用户只需要一个密码,因此需要使用该权限来操作您自己的二级密码。

    • 如果允许某个帐户操作所有帐户的辅助密码,则应授予其 CREATE USER 权限,而不是 APPLICATION_PASSWORD_ADMIN

read_only 启用了系统变量, ALTER USER 另外需要 CONNECTION_ADMIN SUPER 特权。

默认情况下,如果您尝试修改不存在的用户,则会发生错误。 如果 IF EXISTS 给出了 子句,则该语句会为每个不存在的命名用户生成警告,而不是错误。

重要

在某些情况下, ALTER USER 可以在历史文件中记录在服务器日志中或客户端上 ~/.mysql_history ,这意味着任何对该信息具有读访问权限的人都可以读取明文密码。 有关服务器日志发生的条件以及如何控制它的信息,请参见 第6.1.2.3节“密码和日志记录” 有关客户端日志记录的类似信息,请参见 第4.5.1.3节“mysql客户端日志记录”

ALTER USER 声明 有几个方面 ,在以下主题下描述:

更改用户概述

对于每个受影响的帐户, ALTER USER 修改 mysql.user 系统表中 的相应行 以反映语句中指定的属性。 未指定的属性保留其当前值。

每个帐户名称使用 第6.2.4节“指定帐户名称”中 所述的格式 帐户名的主机名部分(如果省略)默认为 '%' 还可以指定 CURRENT_USER CURRENT_USER() 引用与当前会话相关联的帐户。

仅对于一种语法,可以使用以下 USER() 函数 指定帐户

ALTER USER USER()通过' auth_string' 标识;

此语法可以更改您自己的密码,而无需按字面指定您的帐户。 (语法还支持 REPLACE RETAIN CURRENT PASSWORD 以及 DISCARD OLD PASSWORD 在所描述的条款 ALTER用户认证选项 。)

对于 ALTER USER 允许 auth_option 值遵循 user 值的 语法, auth_option 通过指定帐户身份验证插件,凭据(例如,密码)或两者来指示帐户如何进行身份验证。 每个 auth_option 值适用 到一个名为的前一个帐户。

遵循 user 规范,该语句可能包括SSL / TLS,资源限制,密码管理和锁定属性的选项。 所有此类选项 对于语句 都是 全局的 ,并适用于语句中指定的 所有 帐户。

示例:更改帐户密码并使其过期。 因此,用户必须使用指定的密码连接,并在下一次连接时选择一个新密码:

更改用户'jeffrey'@'localhost'new_password'密码出现'识别;

示例:修改帐户以使用 sha256_password 身份验证插件和给定密码。 要求每180天选择一个新密码:

更改用户'jeffrey'@'localhost'
  用sha256_password BY' new_password' 识别
  密码EXPIRE间隔180天;

示例:锁定或解锁帐户:

ALTER USER'jeffrey'@'localhost'ACCOUNT LOCK;
ALTER USER'jeffrey'@'localhost'ACCOUNT UNLOCK;

示例:要求帐户使用SSL进行连接,并建立每小时20个连接的限制:

更改用户'jeffrey'@'localhost'
  使用MAX_CONNECTIONS_PER_HOUR 20要求SSL;

示例:更改多个帐户,指定一些每帐户属性和一些全局属性:

更改用户
  '杰弗里' @ 'localhost' 的
    由' jeffrey_new_password' 识别
  '珍妮' @ 'localhost' 的,
  '乔希' @ 'localhost' 的
    由' josh_new_password' 识别
    替换' josh_current_password'
    保留当前密码
  使用MAX_USER_CONNECTIONS 2要求SSL
  密码历史5;

以下 IDENTIFIED BY jeffrey 仅适用于其前一个帐户,因此它将密码更改为 仅适用于 因为 ,没有每个帐户值(因此保持密码不变)。 对于 建立新密码( ), 指定用于验证发出该 语句 的用户是否 知道当前密码( ),并且该当前密码也保留为帐户二级密码。 (因此, 可以连接主密码或二级密码。) 'jeffrey_new_password' jeffrey jeanne josh IDENTIFIED BY 'josh_new_password' REPLACE ALTER USER 'josh_current_password' josh

其余属性全局应用于语句中指定的所有帐户,因此对于两个帐户:

  • 需要连接才能使用SSL。

  • 该帐户最多可用于两个同时连接。

  • 密码更改无法重用五个最新密码中的任何一个。

示例:丢弃二级密码 josh ,只保留帐户的主密码:

ALTER USER'josh'@'localhost'DISCARD OLD PASSWORD;

在没有特定类型的期权的情况下,账户在这方面保持不变。 例如,如果没有锁定选项,则不会更改帐户的锁定状态。

更改用户身份验证选项

帐户名后面可能是一个 auth_option 身份验证选项,用于指定帐户身份验证插件,凭据或两者。 它还可能包含一个password-verification子句,用于指定要替换的帐户当前密码,以及用于管理帐户是否具有二级密码的子句。

注意

密码验证次密码条款仅适用于内部存储凭据的账户 mysql.user 系统表( mysql_native_password sha256_password ,或 caching_sha2_password )。 对于使用对外部凭据系统执行身份验证的插件的帐户,还必须在该系统外部处理密码管理。

  • auth_plugin 命名一个身份验证插件。 插件名称可以是带引号的字符串文字或不带引号的名称。 插件名称存储在 系统表 plugin 列中 mysql.user

    对于 auth_option 未指定身份验证插件的语法,默认插件由 default_authentication_plugin 系统变量 的值指示 有关每个插件的说明,请参见 第6.4.1节“身份验证插件”

  • 凭据存储在 mysql.user 系统表中。 值指定帐户凭据,无论是作为明文(未加密)的字符串或由与该帐户,分别相关联的认证插件所预期的格式散列: 'auth_string'

    • 对于使用的语法, 字符串是明文,并传递给身份验证插件以进行可能的散列。 插件返回的结果存储在 表中。 插件可以使用指定的值,在这种情况下不会发生散列。 BY 'auth_string' mysql.user

    • 对于使用的语法, 假定该字符串已经采用认证插件所需的格式,并按原样存储在 表中。 如果插件需要散列值,则必须以适合插件的格式对值进行散列处理。 否则,该插件无法使用该值,并且不会发生客户端连接的正确身份验证。 AS 'auth_string' mysql.user

      从MySQL 8.0.17开始,散列字符串可以是字符串文字或十六进制值。 后者对应于 启用系统变量 SHOW CREATE USER 时包含不可打印字符的密码哈希 显示的值的类型 print_identified_with_as_hex

    • 如果身份验证插件不执行对身份验证字符串的散列,则 子句具有相同的效果:将身份验证字符串存储在 系统表中。 BY 'auth_string' AS 'auth_string' mysql.user

  • 子句从MySQL 8.0.13开始提供。 如果给出: REPLACE 'current_auth_string'

    • REPLACE 指定要替换的帐户当前密码,作为明文(未加密)字符串。

    • 如果需要更改密码以指定当前密码,则必须提供该条款,作为验证尝试进行更改的用户实际知道当前密码的验证。

    • 如果帐户的密码更改可能但不需要指定当前密码,则该子句是可选的。

    • 如果给出了该子句但该语句与当前密码不匹配,则该语句失败,即使该子句是可选的。

    • REPLACE 只有在更改当前用户的帐户密码时才能指定。

    有关通过指定当前密码进行密码验证的更多信息,请参见 第6.2.15节“密码管理”

  • RETAIN CURRENT PASSWORD DISCARD OLD PASSWORD 条款实行双重密码功能,并从MySQL 8.0.14的。 两者都是可选的,但如果给出,则具有以下效果:

    • RETAIN CURRENT PASSWORD 保留帐户当前密码作为其辅助密码,替换任何现有的二级密码。 新密码将成为主密码,但客户端可以使用该帐户使用主密码或辅助密码连接到服务器。 (例外:如果 ALTER USER 语句 指定的新密码 为空,则辅助密码也会变为空,即使 RETAIN CURRENT PASSWORD 已给出。)

    • 如果 RETAIN CURRENT PASSWORD 为具有空主密码的帐户 指定 ,则该语句将失败。

    • 如果帐户具有辅助密码并且您在未指定 RETAIN CURRENT PASSWORD 情况下更改其主密码 ,则辅助密码将保持不变。

    • 如果更改分配给该帐户的身份验证插件,则会丢弃该辅助密码。 如果更改身份验证插件并指定 RETAIN CURRENT PASSWORD ,则语句将失败。

    • DISCARD OLD PASSWORD 丢弃二级密码(如果存在)。 该帐户仅保留其主密码,客户端可以使用该帐户仅使用主密码连接到服务器。

    有关使用双密码的更多信息,请参见 第6.2.15节“密码管理”

ALTER USER 允许这些 auth_option 语法:

  • IDENTIFIED BY 'auth_string' [REPLACE 'current_auth_string'] [RETAIN CURRENT PASSWORD]

    将帐户身份验证插件设置为默认插件,将明文 传递 给插件以进行可能的散列,并将结果存储在 系统表 的帐户行中 'auth_string' mysql.user

    REPLACE 如果给出 子句,则指定帐户当前密码,如本节前面所述。

    RETAIN CURRENT PASSWORD 如果给出 子句,则会将帐户当前密码保留为其辅助密码,如本节前面所述。

  • IDENTIFIED WITH auth_plugin

    将帐户身份验证插件设置为 auth_plugin ,将凭据清除为空字符串(凭据与旧的身份验证插件相关联,而不是新的身份验证插件),并将结果存储在 mysql.user 系统表 的帐户行中

    此外,密码标记为已过期。 用户必须在下次连接时选择一个新的。

  • IDENTIFIED WITH auth_plugin BY 'auth_string' [REPLACE 'current_auth_string'] [RETAIN CURRENT PASSWORD]

    将帐户身份验证插件设置为 auth_plugin ,将明文 传递 给插件以进行可能的散列,并将结果存储在 系统表 的帐户行中 'auth_string' mysql.user

    REPLACE 如果给出 子句,则指定帐户当前密码,如本节前面所述。

    RETAIN CURRENT PASSWORD 如果给出 子句,则会将帐户当前密码保留为其辅助密码,如本节前面所述。

  • IDENTIFIED WITH auth_plugin AS 'auth_string'

    将帐户身份验证插件设置为 auth_plugin 并存储 帐户行中 如果插件需要散列字符串,则假定该字符串已经以插件所需的格式进行了散列。 'auth_string' mysql.user

  • DISCARD OLD PASSWORD

    丢弃帐户二级密码(如果有),如本节前面所述。

示例:将密码指定为明文; 使用默认插件:

更改用户'jeffrey'@'localhost'
  识别' password';

示例:指定身份验证插件以及明文密码值:

更改用户'jeffrey'@'localhost'
  使用mysql_native_password标识
             BY' password';

示例:与前面的示例类似,但另外,将当前密码指定为明文值,以满足进行更改的用户知道该密码的任何帐户要求:

更改用户'jeffrey'@'localhost'
  使用mysql_native_password标识
             BY' password'
             替换' current_password';

除非当前用户 jeffrey 因为 REPLACE 仅允许更改当前用户的密码, 否则上述语句将失败

示例:建立新的主密码并将现有密码保留为辅助密码:

更改用户'jeffrey'@'localhost'
  由' new_password' 识别
  保留当前密码;

示例:丢弃二级密码,只保留帐户的主密码:

ALTER USER'jeffery'@'localhost'DISCARD OLD PASSWORD;

示例:指定身份验证插件以及散列密码值:

更改用户'jeffrey'@'localhost'
  使用mysql_native_password标识
             AS'* 6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4';

有关设置密码和身份验证插件的其他信息,请参见 第6.2.14节“分配帐户密码” 第6.2.17节“可插入身份验证”

ALTER USER角色选项

ALTER USER ... DEFAULT ROLE 定义当用户连接到服务器并进行身份验证时,或者用户 SET ROLE DEFAULT 在会话期间 执行 语句 时,哪些角色变为活动状态

ALTER USER ... DEFAULT ROLE 是替代语法 SET DEFAULT ROLE (参见 第13.7.1.9节“SET DEFAULT ROLE语法” )。 但是, ALTER USER 可以仅为单个用户 SET DEFAULT ROLE 设置默认值 ,而 可以为多个用户设置默认值。 另一方面,您可以指定 语句 CURRENT_USER 的用户名 ALTER USER ,而不能用于 SET DEFAULT ROLE

每个用户帐户名称使用前面描述的格式。

每个角色名称使用 第6.2.5节“指定角色名称”中 描述的格式 例如:

ALTER USER'joe'@'10.0.0.1'DEFAULT ROLE管理员,开发人员;

角色名称的主机名部分(如果省略)默认为 '%'

DEFAULT ROLE 关键字 后面的子句 允许这些值:

  • NONE :将默认值设置为 NONE (无角色)。

  • ALL :将默认值设置为授予该帐户的所有角色。

  • role [, role ] ... :将默认值设置为命名角色,该角色必须存在并在执行时授予帐户 ALTER USER ... DEFAULT ROLE

更改用户SSL / TLS选项

除了基于用户名和凭据的常规身份验证之外,MySQL还可以检查X.509证书属性。 有关在MySQL中使用SSL / TLS的背景信息,请参见 第6.3节“使用加密连接”

要为MySQL帐户指定SSL / TLS相关选项,请使用 REQUIRE 指定一个或多个 tls_option 子句

REQUIRE 选项 顺序 无关紧要,但不能指定选项两次。 AND 关键字是可选之间 REQUIRE 选择。

ALTER USER 允许这些 tls_option 值:

  • NONE

    表示该语句指定的所有帐户都没有SSL或X.509要求。 如果用户名和密码有效,则允许未加密的连接。 如果客户端具有适当的证书和密钥文件,则可以在客户端选择使用加密连接。

    更改用户'jeffrey'@'localhost'无需提供;
    

    客户端默认尝试建立安全连接。 对于具有 REQUIRE NONE 此功能的 客户端, 如果无法建立安全连接,则连接尝试将回退到未加密的连接。 要求加密连接,客户端只需指定 --ssl-mode=REQUIRED 选项; 如果无法建立安全连接,则连接尝试失败。

  • SSL

    告知服务器仅允许该语句命名的所有帐户的加密连接。

    更改用户'jeffrey'@'localhost'需要SSL;
    

    客户端默认尝试建立安全连接。 对于具有的帐户, REQUIRE SSL 如果无法建立安全连接,则连接尝试将失败。

  • X509

    对于语句指定的所有帐户,要求客户端提供有效证书,但确切的证书,颁发者和主题无关紧要。 唯一的要求是应该可以使用其中一个CA证书验证其签名。 使用X.509证书始终意味着加密,因此 SSL 在这种情况下不需要 选项。

    ALTER USER'jeffrey'@'localhost'REQUIRE X509;
    

    对于帐户 REQUIRE X509 ,客户必须指定 连接 --ssl-key --ssl-cert 选项。 (建议但不要求 --ssl-ca 也要指定,以便可以验证服务器提供的公共证书。)这是正确的 ISSUER SUBJECT 因为这些 REQUIRE 选项意味着要求 X509

  • ISSUER 'issuer'

    对于语句指定的所有帐户,要求客户端提供CA颁发的有效X.509证书 如果客户端提供的证书有效但具有不同的颁发者,则服务器拒绝该连接。 使用X.509证书始终意味着加密,因此 在这种情况下不需要 选项。 'issuer' SSL

    更改用户'jeffrey'@'localhost'
      要求发行人'/ C = SE / ST =斯德哥尔摩/ L =斯德哥尔摩/
        O=MySQL/CN=CA/emailAddress=ca@example.com“;
    

    因为 ISSUER 暗示了要求 X509 ,客户必须指定 --ssl-key --ssl-cert 连接的选项。 (建议但不要求 --ssl-ca 也要指定,以便验证服务器提供的公共证书。)

  • SUBJECT 'subject'

    对于语句指定的所有帐户,要求客户端提供包含主题的有效X.509证书 subject 如果客户端提供的证书有效但主题不同,则服务器会拒绝该连接。 使用X.509证书始终意味着加密,因此 SSL 在这种情况下不需要 选项。

    更改用户'jeffrey'@'localhost'
      要求主题'/ C = SE / ST =斯德哥尔摩/ L =斯德哥尔摩/
        O = MySQL演示客户端证书/
        CN=client/emailAddress=client@example.com“;
    

    MySQL 对证书 中的 值进行 简单的字符串比较 ,因此必须完全按照证书中的名称给出字母和组件排序。 'subject'

    因为 SUBJECT 暗示了要求 X509 ,客户必须指定 --ssl-key --ssl-cert 连接的选项。 (建议但不要求 --ssl-ca 也要指定,以便验证服务器提供的公共证书。)

  • CIPHER 'cipher'

    对于语句指定的所有帐户,需要特定的密码方法来加密连接。 需要此选项以确保使用足够强度的密码和密钥长度。 如果使用使用短加密密钥的旧算法,则加密可能很弱。

    更改用户'jeffrey'@'localhost'
      需要密码'EDH-RSA-DES-CBC3-SHA';
    

SUBJECT ISSUER CIPHER 选项可以在组合中的 REQUIRE 条款:

更改用户'jeffrey'@'localhost'
  要求主题'/ C = SE / ST =斯德哥尔摩/ L =斯德哥尔摩/
    O = MySQL演示客户端证书/
    CN=client/emailAddress=client@example.com”
  AND ISSUER'/ C = SE / ST =斯德哥尔摩/ L =斯德哥尔摩/
    O=MySQL/CN=CA/emailAddress=ca@example.com”
  和CIPHER'EDH-RSA-DES-CBC3-SHA';
更改用户资源限制选项

可以对帐户使用服务器资源 设置限制 ,如 第6.2.20节“设置帐户资源限制”中所述 为此,请使用 WITH 指定一个或多个 resource_option 子句

WITH 选项 顺序 无关紧要,除非多次指定给定资源限制,最后一个实例优先。

ALTER USER 允许这些 resource_option 值:

  • MAX_QUERIES_PER_HOUR count MAX_UPDATES_PER_HOUR count MAX_CONNECTIONS_PER_HOUR count

    对于语句指定的所有帐户,这些选项限制在任何给定的一小时内允许每个帐户访问服务器的查询,更新和连接的数量。 如果 count 0 (默认值),则表示帐户没有限制。

  • MAX_USER_CONNECTIONS count

    对于语句指定的所有帐户,限制每个帐户与服务器的最大并发连接数。 非零 count 指定帐户的限制。 如果 count 0 (默认值),则服务器根据 max_user_connections 系统变量 的全局值确定帐户的同时连接数 如果 max_user_connections 也为零,则帐户没有限制。

例:

更改用户'jeffrey'@'localhost'
  MAX_QUERIES_PER_HOUR 500 MAX_UPDATES_PER_HOUR 100;
更改用户密码管理选项

ALTER USER 支持多个 password_option 密码管理值:

  • 密码过期选项:您可以手动过期帐户密码并建立密码过期策略。 策略选项不会使密码失效。 相反,它们根据密码年龄确定服务器如何将自动过期应用于帐户,密码年龄是根据最近帐户密码更改的日期和时间进行评估的。

  • 密码重用选项:您可以根据密码更改次数,已用时间或两者来限制密码重用。

  • 密码验证所需选项:您可以指示尝试更改帐户密码是否必须指定当前密码,以验证尝试进行更改的用户是否实际知道当前密码。

本节介绍密码管理选项的语法。 有关建立密码管理策略的信息,请参见 第6.2.15节“密码管理”

如果给定类型(多重密码管理选项 PASSWORD EXPIRE PASSWORD HISTORY PASSWORD REUSE INTERVAL PASSWORD REQUIRE 被指定),最后一个优先。

注意

密码管理选项仅适用于内部存储凭据的账户 mysql.user 系统表( mysql_native_password sha256_password ,或 caching_sha2_password )。 对于使用对外部凭据系统执行身份验证的插件的帐户,还必须在该系统外部处理密码管理。

如果帐户密码手动过期或密码年龄被认为大于其自动过期策略的允许生命周期,则客户端的密码已过期。 在这种情况下,服务器会断开客户端连接或限制允许的操作(请参见 第6.2.16节“过期密码的服务器处理” )。 受限客户端执行的操作会导致错误,直到用户建立新的帐户密码。

注意

可以 通过将密码设置为其当前值 重置 密码。 作为一个好的政策问题,最好选择不同的密码。 DBA可以通过建立适当的密码重用策略来强制执行非重用。 请参阅 密码重用策略

ALTER USER 允许这些 password_option 值来控制密码到期:

  • PASSWORD EXPIRE

    立即为该语句指定的所有帐户标记密码已过期。

    ALTER USER'jeffrey'@'localhost'PASSWORD EXPIRE;
    
  • PASSWORD EXPIRE DEFAULT

    设置由语句命名的所有帐户,以便应用全局过期策略,如 default_password_lifetime 系统变量 所指定

    ALTER USER'jeffrey'@'localhost'PASSWORD EXPIRE DEFAULT;
    
  • PASSWORD EXPIRE NEVER

    此到期选项会覆盖该语句指定的所有帐户的全局策略。 对于每个,它会禁用密码到期,以便密码永不过期。

    ALTER USER'jeffrey'@'localhost'PASSWORD EXPIRE NEVER;
    
  • PASSWORD EXPIRE INTERVAL N DAY

    此到期选项会覆盖该语句指定的所有帐户的全局策略。 对于每个,它将密码生存期设置为 N 天。 以下语句要求密码每180天更改一次:

    ALTER USER'jeffrey'@'localhost'PASSWORD EXPIRE INTERVAL 180天;
    

ALTER USER 允许这些 password_option 值根据所需的最小密码更改次数控制以前密码的重用:

  • PASSWORD HISTORY DEFAULT

    设置由语句命名的所有帐户,以便应用关于密码历史记录长度的全局策略,以禁止在 password_history 系统变量 指定的更改数之前重用密码

    ALTER USER'jeffrey'@'localhost'PASSWORD HISTORY DEFAULT;
    
  • PASSWORD HISTORY N

    此历史记录长度选项会覆盖该语句指定的所有帐户的全局策略。 对于每个密码,它将密码历史记录长度设置为 N 密码,以禁止重用任何 N 最近选择的密码。 以下声明禁止重复使用以前的6个密码:

    ALTER USER'jeffrey'@'localhost'PASSWORD HISTORY 6;
    

ALTER USER 允许这些 password_option 值根据已用时间控制以前密码的重用:

  • PASSWORD REUSE INTERVAL DEFAULT

    设置帐户指定的所有语句,以便应用有关时间的全局策略,以禁止重用比 password_reuse_interval 系统变量 指定的天数更新的密码

    ALTER USER'jeffrey'@'localhost'PASSWORD REUSE INTERVAL DEFAULT;
    
  • PASSWORD REUSE INTERVAL N DAY

    此time-elapsed选项会覆盖该语句指定的所有帐户的全局策略。 对于每个,它将密码重用间隔设置为 N 天,以禁止重用比这多天更新的密码。 以下声明禁止密码重用360天:

    ALTER USER'jeffrey'@'localhost'PASSWORD REUSE INTERVAL 360 DAY;
    

ALTER USER 允许这些 password_option 值来控制是否尝试更改帐户密码必须指定当前密码,以验证尝试进行更改的用户是否实际知道当前密码:

  • PASSWORD REQUIRE CURRENT

    此验证选项会覆盖该语句指定的所有帐户的全局策略。 对于每个,它要求密码更改指定当前密码。

    更改用户'jeffrey'@'localhost'密码请求当前;
    
  • PASSWORD REQUIRE CURRENT OPTIONAL

    此验证选项会覆盖该语句指定的所有帐户的全局策略。 对于每个,它不要求密码更改指定当前密码。 (可能但不需要提供当前密码。)

    更改用户'jeffrey'@'localhost'密码要求当前可选;
    
  • PASSWORD REQUIRE CURRENT DEFAULT

    设置帐户命名的所有语句,以便应用关于密码验证的全局策略,如 password_require_current 系统变量 所指定

    更改用户'jeffrey'@'localhost'密码请求当前默认值;
    
ALTER USER帐户锁定选项

MySQL支持使用 ACCOUNT LOCK ACCOUNT UNLOCK 选项 进行帐户锁定和解锁 ,这些选项指定帐户的锁定状态。 有关其他讨论,请参见 第6.2.19节“帐户锁定”

如果指定了多个帐户锁定选项,则最后一个优先。

ALTER USER二进制日志记录

ALTER USER 如果成功则写入二进制日志,但如果失败则不写入; 在这种情况下,发生回滚并且不进行任何更改。 写入二进制日志的语句包括所有已命名的用户。 如果 IF EXISTS 给出 条款,则甚至包括不存在且未被更改的用户。

如果原始语句更改了用户的凭据,则写入二进制日志的语句将为该用户指定适用的身份验证插件,确定如下:

  • 如果指定了一个插件,则在原始语句中命名。

  • 否则,如果用户存在,则与用户帐户关联的插件,如果用户不存在,则为默认的身份验证插件。 (如果写入二进制日志的语句必须为用户指定特定的身份验证插件,请将其包含在原始语句中。)

如果服务器为写入二进制日志的语句中的任何用户添加了默认身份验证插件,则会向命名这些用户的错误日志写入警告。

13.7.1.2 CREATE ROLE语法

创造角色[如果不是EXISTS] role[,role] ......

CREATE ROLE 创建一个或多个角色,这些角色被命名为特权集合。 要使用此语句,您必须具有全局 CREATE ROLE CREATE USER 特权。 read_only 启用了系统变量, CREATE ROLE 另外需要 CONNECTION_ADMIN SUPER 特权。

创建时的角色已锁定,没有密码,并被分配了默认的身份验证插件。 ALTER USER 具有全局 CREATE USER 权限 的用户 可以稍后使用该 语句 更改这些角色属性 。)

CREATE ROLE 要么成功执行所有已命名的角色,要么回滚,如果发生任何错误,则无效。 默认情况下,如果您尝试创建已存在的角色,则会发生错误。 如果 IF NOT EXISTS 给出了 子句,则该语句会为已存在的每个已命名角色生成警告,而不是错误。

如果成功,则将语句写入二进制日志,但如果失败则不写入; 在这种情况下,发生回滚并且不进行任何更改。 写入二进制日志的语句包括所有命名角色。 如果 IF NOT EXISTS 给出 了该 子句,则包括已存在且未创建的角色。

每个角色名称使用 第6.2.5节“指定角色名称”中 描述的格式 例如:

CREATE ROLE'管理员','开发人员';
CREATE ROLE'webapp'@'localhost';

角色名称的主机名部分(如果省略)默认为 '%'

有关角色使用示例,请参见 第6.2.10节“使用角色”

13.7.1.3 CREATE USER语法

创建用户[如果不是EXISTS]
     user[ auth_option] [,user[ auth_option]] ......
    默认角色role[,role] ......
    [要求{无|] tls_option[[AND] tls_option] ...}]
    [WITH resource_option[ resource_option] ...]
    [ password_option| lock_option] ......

user
    (参见第6.2.4节“指定帐户名”

auth_option:{
    由' auth_string' 识别
  | auth_plugin
  |来识别 通过auth_plugin' auth_string'确认
  | auth_plugin' auth_string''确认
}

tls_option:{
   SSL
 | X509
 | CIPHER' cipher'
 | 发行人' issuer'
 | 主题' subject'
}

resource_option:{
    MAX_QUERIES_PER_HOUR count
  | MAX_UPDATES_PER_HOUR count
  | MAX_CONNECTIONS_PER_HOUR count
  | MAX_USER_CONNECTIONScount
}

password_option:{
    PASSWORD EXPIRE [默认值] 永远不会 间隔日N]
  | 密码历史{默认| N}
  | PASSWORD REUSE INTERVAL {默认| N天}
  | 密码要求当前[默认值] 可选的]
}

lock_option:{
    账户锁
  | 帐户解锁
}

CREATE USER 语句创建新的MySQL帐户。 它可以为新帐户建立身份验证,角色,SSL / TLS,资源限制和密码管理属性。 它还控制帐户最初是锁定还是解锁。

要使用 CREATE USER ,您必须具有全局 CREATE USER 特权或 系统数据库 INSERT 特权 mysql read_only 启用了系统变量, CREATE USER 另外需要 CONNECTION_ADMIN SUPER 特权。

CREATE USER 对所有命名用户成功或回滚,如果发生任何错误,则无效。 默认情况下,如果您尝试创建已存在的用户,则会发生错误。 如果 IF NOT EXISTS 给出了 子句,则该语句会为已存在的每个已命名用户生成警告,而不是错误。

重要

在某些情况下, CREATE USER 可以在历史文件中记录在服务器日志中或客户端上 ~/.mysql_history ,这意味着任何对该信息具有读访问权限的人都可以读取明文密码。 有关服务器日志发生的条件以及如何控制它的信息,请参见 第6.1.2.3节“密码和日志记录” 有关客户端日志记录的类似信息,请参见 第4.5.1.3节“mysql客户端日志记录”

CREATE USER 声明 有几个方面 ,在以下主题下描述:

创建用户概述

对于每个帐户, CREATE USER mysql.user 系统表中 创建一个新行 帐户行反映了语句中指定的属性。 未指定的属性设置为其默认值:

  • 身份验证:由 default_authentication_plugin 系统变量 定义的身份验证插件 和空凭据

  • 默认角色: NONE

  • SSL / TLS: NONE

  • 资源限制:无限制

  • 密码管理: PASSWORD EXPIRE DEFAULT PASSWORD HISTORY DEFAULT PASSWORD REUSE INTERVAL DEFAULT PASSWORD REQUIRE CURRENT DEFAULT

  • 帐户锁定: ACCOUNT UNLOCK

首次创建时,帐户没有权限,默认角色为 NONE 要分配权限或角色,请使用该 GRANT 语句。

每个帐户名称使用 第6.2.4节“指定帐户名称”中 所述的格式 例如:

创建用户'jeffrey'@'localhost'标识' password';

帐户名的主机名部分(如果省略)默认为 '%'

user 命名帐户的 每个 值后面都可以跟一个可选 auth_option 值,该值指示帐户的身份验证方式。 这些值可以指定帐户身份验证插件和凭据(例如,密码)。 每个 auth_option 值适用 到一个名为的前一个帐户。

遵循 user 规范,该语句可能包括SSL / TLS,资源限制,密码管理和锁定属性的选项。 所有此类选项 对于语句 都是 全局的 ,并适用于语句中指定的 所有 帐户。

示例:创建使用默认身份验证插件和给定密码的帐户。 标记密码已过期,以便用户必须在第一次连接到服务器时选择一个新密码:

创建用户'jeffrey'@'localhost'new_password'密码出现'识别;

示例:创建使用 sha256_password 身份验证插件和给定密码 的帐户 要求每180天选择一个新密码:

创建用户'jeffrey'@'localhost'
  用sha256_password BY' new_password' 识别
  密码EXPIRE间隔180天;

示例:创建多个帐户,指定一些每帐户属性和一些全局属性:

创建用户
  'jeffrey'@'localhost'用mysql_native_password识别
                                   BY' new_password1',
  'jeanne'@'localhost'用sha256_password识别
                                  BY' new_password2'
  要求X509使用MAX_QUERIES_PER_HOUR 60
  密码历史5
  账户锁;

每个 auth_option 值( IDENTIFIED WITH ... BY 在这种情况下)仅适用于紧接在其之前命名的帐户,因此每个帐户使用紧随其后的身份验证插件和密码。

其余属性全局应用于语句中指定的所有帐户,因此对于两个帐户:

  • 必须使用有效的X.509证书进行连接。

  • 每小时最多允许60个查询。

  • 密码更改无法重用五个最新密码中的任何一个。

  • 该帐户最初是锁定的,因此它实际上是占位符,在管理员解锁之前无法使用。

创建用户身份验证选项

帐户名后面可能是一个 auth_option 身份验证选项,用于指定帐户身份验证插件,凭据或两者:

  • auth_plugin 命名一个身份验证插件。 插件名称可以是带引号的字符串文字或不带引号的名称。 插件名称存储在 系统表 plugin 列中 mysql.user

    对于 auth_option 未指定身份验证插件的语法,默认插件由 default_authentication_plugin 系统变量 的值指示 有关每个插件的说明,请参见 第6.4.1节“身份验证插件”

  • 凭据存储在 mysql.user 系统表中。 值指定帐户凭据,无论是作为明文(未加密)的字符串或由与该帐户,分别相关联的认证插件所预期的格式散列: 'auth_string'

    • 对于使用的语法, 字符串是明文,并传递给身份验证插件以进行可能的散列。 插件返回的结果存储在 表中。 插件可以使用指定的值,在这种情况下不会发生散列。 BY 'auth_string' mysql.user

    • 对于使用的语法, 假定该字符串已经采用认证插件所需的格式,并按原样存储在 表中。 如果插件需要散列值,则必须以适合插件的格式对值进行散列处理。 否则,该插件无法使用该值,并且不会发生客户端连接的正确身份验证。 AS 'auth_string' mysql.user

      从MySQL 8.0.17开始,散列字符串可以是字符串文字或十六进制值。 后者对应于 启用系统变量 SHOW CREATE USER 时包含不可打印字符的密码哈希 显示的值的类型 print_identified_with_as_hex

    • 如果身份验证插件不执行身份验证字符串的哈希,则 子句具有相同的效果:身份验证字符串的存储在 表中。 BY 'auth_string' AS 'auth_string' mysql.user

CREATE USER 允许这些 auth_option 语法:

  • IDENTIFIED BY 'auth_string'

    将帐户身份验证插件设置为默认插件,将明文 传递 给插件以进行可能的散列,并将结果存储在 系统表 的帐户行中 'auth_string' mysql.user

  • IDENTIFIED WITH auth_plugin

    将帐户身份验证插件设置为 auth_plugin ,将凭据清除为空字符串,并将结果存储在 mysql.user 系统表 的帐户行中

  • IDENTIFIED WITH auth_plugin BY 'auth_string'

    将帐户身份验证插件设置为 auth_plugin ,将明文 传递 给插件以进行可能的散列,并将结果存储在 系统表 的帐户行中 'auth_string' mysql.user

  • IDENTIFIED WITH auth_plugin AS 'auth_string'

    将帐户身份验证插件设置为 auth_plugin 并存储 帐户行中 如果插件需要散列字符串,则假定该字符串已经以插件所需的格式进行了散列。 'auth_string' mysql.user

示例:将密码指定为明文; 使用默认插件:

创建用户'jeffrey'@'localhost'
  识别' password';

示例:指定身份验证插件以及明文密码值:

创建用户'jeffrey'@'localhost'
  使用mysql_native_password BY' password' 识别;

在每种情况下,存储在帐户行中的密码值是在 与帐户关联的身份验证插件进行哈希处理后 的明文值 'password'

有关设置密码和身份验证插件的其他信息,请参见 第6.2.14节“分配帐户密码” 第6.2.17节“可插入身份验证”

创建用户角色选项

DEFAULT ROLE 子句定义当用户连接到服务器并进行身份验证时,或者用户 SET ROLE DEFAULT 在会话期间 执行 语句 时,哪些角色变为活动状态

每个角色名称使用 第6.2.5节“指定角色名称”中 描述的格式 例如:

CREATE USER'joe'@'10.0.0.1'DEFAULT ROLE管理员,开发人员;

角色名称的主机名部分(如果省略)默认为 '%'

DEFAULT ROLE 子句允许一个或多个以逗号分隔的角色名称的列表。 CREATE USER 执行 时不需要存在这些角色

创建用户SSL / TLS选项

除了基于用户名和凭据的常规身份验证之外,MySQL还可以检查X.509证书属性。 有关在MySQL中使用SSL / TLS的背景信息,请参见 第6.3节“使用加密连接”

要为MySQL帐户指定SSL / TLS相关选项,请使用 REQUIRE 指定一个或多个 tls_option 子句

REQUIRE 选项 顺序 无关紧要,但不能指定选项两次。 AND 关键字是可选之间 REQUIRE 选择。

CREATE USER 允许这些 tls_option 值:

  • NONE

    表示该语句指定的所有帐户都没有SSL或X.509要求。 如果用户名和密码有效,则允许未加密的连接。 如果客户端具有适当的证书和密钥文件,则可以在客户端选择使用加密连接。

    创建用户'jeffrey'@'localhost'无需任何操作;
    

    客户端默认尝试建立安全连接。 对于具有 REQUIRE NONE 此功能的 客户端, 如果无法建立安全连接,则连接尝试将回退到未加密的连接。 要求加密连接,客户端只需指定 --ssl-mode=REQUIRED 选项; 如果无法建立安全连接,则连接尝试失败。

    NONE 如果未 REQUIRE 指定 与SSL相关的 选项, 则为默认值

  • SSL

    告知服务器仅允许该语句命名的所有帐户的加密连接。

    创建用户'jeffrey'@'localhost'需要SSL;
    

    客户端默认尝试建立安全连接。 对于具有的帐户, REQUIRE SSL 如果无法建立安全连接,则连接尝试将失败。

  • X509

    对于语句指定的所有帐户,要求客户端提供有效证书,但确切的证书,颁发者和主题无关紧要。 唯一的要求是应该可以使用其中一个CA证书验证其签名。 使用X.509证书始终意味着加密,因此 SSL 在这种情况下不需要 选项。

    CREATE USER'jeffrey'@'localhost'REQUIRE X509;
    

    对于帐户 REQUIRE X509 ,客户必须指定 连接 --ssl-key --ssl-cert 选项。 (建议但不要求 --ssl-ca 也要指定,以便可以验证服务器提供的公共证书。)这是正确的 ISSUER SUBJECT 因为这些 REQUIRE 选项意味着要求 X509

  • ISSUER 'issuer'

    对于语句指定的所有帐户,要求客户端提供CA颁发的有效X.509证书 如果客户端提供的证书有效但具有不同的颁发者,则服务器拒绝该连接。 使用X.509证书始终意味着加密,因此 在这种情况下不需要 选项。 'issuer' SSL

    创建用户'jeffrey'@'localhost'
      要求发行人'/ C = SE / ST =斯德哥尔摩/ L =斯德哥尔摩/
        O=MySQL/CN=CA/emailAddress=ca@example.com“;
    

    因为 ISSUER 暗示了要求 X509 ,客户必须指定 --ssl-key --ssl-cert 连接的选项。 (建议但不要求 --ssl-ca 也要指定,以便验证服务器提供的公共证书。)

  • SUBJECT 'subject'

    对于语句指定的所有帐户,要求客户端提供包含主题的有效X.509证书 subject 如果客户端提供的证书有效但主题不同,则服务器会拒绝该连接。 使用X.509证书始终意味着加密,因此 SSL 在这种情况下不需要 选项。

    创建用户'jeffrey'@'localhost'
      要求主题'/ C = SE / ST =斯德哥尔摩/ L =斯德哥尔摩/
        O = MySQL演示客户端证书/
        CN=client/emailAddress=client@example.com“;
    

    MySQL 对证书 中的 值进行 简单的字符串比较 ,因此必须完全按照证书中的名称给出字母和组件排序。 'subject'

    因为 SUBJECT 暗示了要求 X509 ,客户必须指定 --ssl-key --ssl-cert 连接的选项。 (建议但不要求 --ssl-ca 也要指定,以便验证服务器提供的公共证书。)

  • CIPHER 'cipher'

    对于语句指定的所有帐户,需要特定的密码方法来加密连接。 需要此选项以确保使用足够强度的密码和密钥长度。 如果使用使用短加密密钥的旧算法,则加密可能很弱。

    创建用户'jeffrey'@'localhost'
      需要密码'EDH-RSA-DES-CBC3-SHA';
    

SUBJECT ISSUER CIPHER 选项可以在组合中的 REQUIRE 条款:

创建用户'jeffrey'@'localhost'
  要求主题'/ C = SE / ST =斯德哥尔摩/ L =斯德哥尔摩/
    O = MySQL演示客户端证书/
    CN=client/emailAddress=client@example.com”
  AND ISSUER'/ C = SE / ST =斯德哥尔摩/ L =斯德哥尔摩/
    O=MySQL/CN=CA/emailAddress=ca@example.com”
  和CIPHER'EDH-RSA-DES-CBC3-SHA';
创建用户资源限制选项

可以对帐户使用服务器资源 设置限制 ,如 第6.2.20节“设置帐户资源限制”中所述 为此,请使用 WITH 指定一个或多个 resource_option 子句

WITH 选项 顺序 无关紧要,除非多次指定给定资源限制,最后一个实例优先。

CREATE USER 允许这些 resource_option 值:

  • MAX_QUERIES_PER_HOUR count MAX_UPDATES_PER_HOUR count MAX_CONNECTIONS_PER_HOUR count

    对于语句指定的所有帐户,这些选项限制在任何给定的一小时内允许每个帐户访问服务器的查询,更新和连接的数量。 如果 count 0 (默认值),则表示帐户没有限制。

  • MAX_USER_CONNECTIONS count

    对于语句指定的所有帐户,限制每个帐户与服务器的最大并发连接数。 非零 count 指定帐户的限制。 如果 count 0 (默认值),则服务器根据 max_user_connections 系统变量 的全局值确定帐户的同时连接数 如果 max_user_connections 也为零,则帐户没有限制。

例:

创建用户'jeffrey'@'localhost'
  MAX_QUERIES_PER_HOUR 500 MAX_UPDATES_PER_HOUR 100;
创建用户密码管理选项

CREATE USER 支持多个 password_option 密码管理值:

  • 密码过期选项:您可以手动过期帐户密码并建立密码过期策略。 策略选项不会使密码失效。 相反,它们根据密码年龄确定服务器如何将自动过期应用于帐户,密码年龄是根据最近帐户密码更改的日期和时间进行评估的。

  • 密码重用选项:您可以根据密码更改次数,已用时间或两者来限制密码重用。

  • 密码验证所需选项:您可以指示尝试更改帐户密码是否必须指定当前密码,以验证尝试进行更改的用户是否实际知道当前密码。

本节介绍密码管理选项的语法。 有关建立密码管理策略的信息,请参见 第6.2.15节“密码管理”

如果给定类型(多重密码管理选项 PASSWORD EXPIRE PASSWORD HISTORY PASSWORD REUSE INTERVAL PASSWORD REQUIRE 被指定),最后一个优先。

注意

密码管理选项仅适用于内部存储凭据的账户 mysql.user 系统表( mysql_native_password sha256_password ,或 caching_sha2_password )。 对于使用对外部凭据系统执行身份验证的插件的帐户,还必须在该系统外部处理密码管理。

如果帐户密码手动过期或密码年龄被认为大于其自动过期策略的允许生命周期,则客户端的密码已过期。 在这种情况下,服务器会断开客户端连接或限制允许的操作(请参见 第6.2.16节“过期密码的服务器处理” )。 受限客户端执行的操作会导致错误,直到用户建立新的帐户密码。

CREATE USER 允许这些 password_option 值来控制密码到期:

  • PASSWORD EXPIRE

    立即为该语句指定的所有帐户标记密码已过期。

    创建用户'jeffrey'@'localhost'PASSWORD EXPIRE;
    
  • PASSWORD EXPIRE DEFAULT

    设置由语句命名的所有帐户,以便应用全局过期策略,如 default_password_lifetime 系统变量 所指定

    创建用户'jeffrey'@'localhost'PASSWORD EXPIRE DEFAULT;
    
  • PASSWORD EXPIRE NEVER

    此到期选项会覆盖该语句指定的所有帐户的全局策略。 对于每个,它会禁用密码到期,以便密码永不过期。

    创建用户'jeffrey'@'localhost'密码永远不会出现;
    
  • PASSWORD EXPIRE INTERVAL N DAY

    此到期选项会覆盖该语句指定的所有帐户的全局策略。 对于每个,它将密码生存期设置为 N 天。 以下语句要求密码每180天更改一次:

    创建用户'jeffrey'@'localhost'密码EXPIRE INTERVAL 180天;
    

CREATE USER 允许这些 password_option 值根据所需的最小密码更改次数控制以前密码的重用:

  • PASSWORD HISTORY DEFAULT

    设置由语句命名的所有帐户,以便应用关于密码历史记录长度的全局策略,以禁止在 password_history 系统变量 指定的更改数之前重用密码

    创建用户'jeffrey'@'localhost'密码历史默认;
    
  • PASSWORD HISTORY N

    此历史记录长度选项会覆盖该语句指定的所有帐户的全局策略。 对于每个密码,它将密码历史记录长度设置为 N 密码,以禁止重用任何 N 最近选择的密码。 以下声明禁止重复使用以前的6个密码:

    创建用户'jeffrey'@'localhost'密码历史6;
    

CREATE USER 允许这些 password_option 值根据已用时间控制以前密码的重用:

  • PASSWORD REUSE INTERVAL DEFAULT

    设置帐户指定的所有语句,以便应用有关时间的全局策略,以禁止重用比 password_reuse_interval 系统变量 指定的天数更新的密码

    创建用户'jeffrey'@'localhost'密码重用间隔默认值;
    
  • PASSWORD REUSE INTERVAL N DAY

    此time-elapsed选项会覆盖该语句指定的所有帐户的全局策略。 对于每个,它将密码重用间隔设置为 N 天,以禁止重用比这多天更新的密码。 以下声明禁止密码重用360天:

    创建用户'jeffrey'@'localhost'密码重新使用INTERVAL 360天;
    

CREATE USER 允许这些 password_option 值来控制是否尝试更改帐户密码必须指定当前密码,以验证尝试进行更改的用户是否实际知道当前密码:

  • PASSWORD REQUIRE CURRENT

    此验证选项会覆盖该语句指定的所有帐户的全局策略。 对于每个,它要求密码更改指定当前密码。

    创建用户'jeffrey'@'localhost'密码请求当前;
    
  • PASSWORD REQUIRE CURRENT OPTIONAL

    此验证选项会覆盖该语句指定的所有帐户的全局策略。 对于每个,它不要求密码更改指定当前密码。 (可能但不需要提供当前密码。)

    创建用户'jeffrey'@'localhost'密码请求当前可选;
    
  • PASSWORD REQUIRE CURRENT DEFAULT

    设置帐户命名的所有语句,以便应用关于密码验证的全局策略,如 password_require_current 系统变量 所指定

    创建用户'jeffrey'@'localhost'密码请求当前默认值;
    
创建用户帐户锁定选项

MySQL支持使用 ACCOUNT LOCK ACCOUNT UNLOCK 选项 进行帐户锁定和解锁 ,这些选项指定帐户的锁定状态。 有关其他讨论,请参见 第6.2.19节“帐户锁定”

如果指定了多个帐户锁定选项,则最后一个优先。

创建用户二进制日志记录

CREATE USER 如果成功则写入二进制日志,但如果失败则不写入; 在这种情况下,发生回滚并且不进行任何更改。 写入二进制日志的语句包括所有已命名的用户。 如果 IF NOT EXISTS 给出 了该 子句,则甚至包括已存在且未创建的用户。

写入二进制日志的语句为每个用户指定一个身份验证插件,确定如下:

  • 如果指定了一个插件,则在原始语句中命名。

  • 否则,默认的身份验证插件。 特别是,如果用户 u1 已经存在并使用非默认身份验证插件,则该语句将写入二进制日志以 CREATE USER IF NOT EXISTS u1 获取默认身份验证插件的名称。 (如果写入二进制日志的语句必须为用户指定非默认身份验证插件,请将其包含在原始语句中。)

如果服务器在写入二进制日志的语句中为任何不存在的用户添加默认身份验证插件,则会向命名这些用户的错误日志写入警告。

13.7.1.4 DROP ROLE语法

DROP ROLE [IF EXISTS] role[,role] ......

DROP ROLE 删除一个或多个角色(命名的特权集合)。 要使用此语句,您必须具有全局 DROP ROLE CREATE USER 特权。 read_only 启用了系统变量, DROP ROLE 另外需要 CONNECTION_ADMIN SUPER 特权。

从MySQL 8.0.16开始,拥有该 CREATE USER 权限的 用户 可以使用此语句删除已锁定或未锁定的帐户。 拥有该 DROP ROLE 权限的 用户 只能使用此语句删除被锁定的帐户(未锁定的帐户可能是用于登录服务器的用户帐户,而不仅仅是作为角色)。

mandatory_roles 无法删除 系统变量值中 命名的角色

DROP ROLE 要么成功执行所有已命名的角色,要么回滚,如果发生任何错误,则无效。 默认情况下,如果您尝试删除不存在的角色,则会发生错误。 如果 IF EXISTS 给出了 子句,则该语句会为每个不存在的命名角色生成警告,而不是错误。

如果成功,则将语句写入二进制日志,但如果失败则不写入; 在这种情况下,发生回滚并且不进行任何更改。 写入二进制日志的语句包括所有命名角色。 如果 IF EXISTS 给出 了该 子句,则包括不存在且未被删除的角色。

每个角色名称使用 第6.2.5节“指定角色名称”中 描述的格式 例如:

DROP ROLE'管理员','开发者';
DROP ROLE'webapp'@'localhost';

角色名称的主机名部分(如果省略)默认为 '%'

已删除角色会自动从已授予角色的任何用户帐户(或角色)中撤消。 在此类帐户的任何当前会话中,其调整的权限从下一个执行的语句开始应用。

有关角色使用示例,请参见 第6.2.10节“使用角色”

13.7.1.5 DROP USER语法

DROP USER [IF EXISTS] user[,user] ......

DROP USER 语句删除一个或多个MySQL帐户及其权限。 它从所有授权表中删除该帐户的权限行。

mandatory_roles 无法删除 系统变量值中 命名的角色

要使用 DROP USER ,您必须具有全局 CREATE USER 特权或 系统数据库 DELETE 特权 mysql read_only 启用了系统变量, DROP USER 另外需要 CONNECTION_ADMIN SUPER 特权。

DROP USER 对所有命名用户成功或回滚,如果发生任何错误,则无效。 默认情况下,如果您尝试删除不存在的用户,则会发生错误。 如果 IF EXISTS 给出了 子句,则该语句会为每个不存在的命名用户生成警告,而不是错误。

如果成功,则将语句写入二进制日志,但如果失败则不写入; 在这种情况下,发生回滚并且不进行任何更改。 写入二进制日志的语句包括所有已命名的用户。 如果 IF EXISTS 给出 了该 子句,则甚至包括不存在且未被丢弃的用户。

每个帐户名称使用 第6.2.4节“指定帐户名称”中 所述的格式 例如:

DROP USER'jeffrey'@'localhost';

帐户名的主机名部分(如果省略)默认为 '%'

重要

DROP USER 不会自动关闭任何打开的用户会话。 相反,如果删除了具有打开会话的用户,则该语句在该用户的会话关闭之前不会生效。 会话关闭后,用户将被删除,该用户下次登录尝试将失败。 这是设计的

DROP USER 不会自动删除或使旧用户创建的数据库或对象无效。 这包括存储的程序或视图, DEFINER 属性为已删除的用户命名。 如果在定义的安全性上下文中执行,则尝试访问此类对象可能会产生错误。 (有关安全上下文的信息,请参见 第24.6节“存储对象访问控制” 。)

13.7.1.6 GRANT语法

GRANT
     priv_type[(column_list)]
      [,priv_type[(column_list)]] ......
    ON [ object_type] priv_level
    TO user_or_role[,user_or_role] ......
    [WITH GRANT OPTION]
    [如 user
        [有角色
            默认
          | 没有
          | 所有
          | 除了role[,role]之外......
          | role[,role] ......
        ]
    ]
}

GRANT PROXY ON user_or_role
    TO user_or_role[,user_or_role] ...
    [WITH GRANT OPTION]

GRANT role[,role] ......
    TO user_or_role[,user_or_role] ......
    [WITH ADMIN OPTION]

object_type:{
  | 功能
  | 程序
}

priv_level:{
    *
  | *。*
  | db_name*。
  | db_name.tbl_name
  | tbl_name
  | db_nameroutine_name
}

user_or_role:{
     user
  |role
}

user
    (参见第6.2.4节“指定帐户名”

role
    (请参见第6.2.5节“指定角色名称”

GRANT 语句为MySQL用户帐户和角色分配权限和角色。 GRANT 声明 有几个方面 ,在以下主题下描述:

GRANT概述

GRANT 语句使系统管理员可以授予权限和角色,这些权限和角色可以授予用户帐户和角色。 这些语法限制适用:

  • GRANT 不能混合在同一语句中授予权限和角色。 给定 GRANT 语句必须授予特权或角色。

  • ON 条款区分该语句是否授予特权或角色:

    • ON ,该声明授予特权。

    • 没有 ON ,该声明授予角色。

    • 允许为帐户分配权限和角色,但必须使用单独的 GRANT 语句,每个语句都具有适合于授予的语法。

有关角色的更多信息,请参阅 第6.2.10节“使用角色”

要使用 GRANT ,您必须拥有该 GRANT OPTION 权限,并且您必须具有您授予的权限。 read_only 启用了系统变量, GRANT 另外需要 CONNECTION_ADMIN SUPER 特权。

GRANT 要么为所有命名用户和角色成功,要么回滚,如果发生任何错误,则无效。 只有当所有命名用户和角色成功时,该语句才会写入二进制日志。

REVOKE 声明与 GRANT 管理员 相关 并使其能够删除帐户权限。 请参见 第13.7.1.8节“REVOKE语法”

每个帐户名称使用 第6.2.4节“指定帐户名称”中 所述的格式 每个角色名称使用 第6.2.5节“指定角色名称”中 描述的格式 例如:

全部授予db1。*给'jeffrey'@'localhost';
GRANT'rort1','role2'TO'user1'@'localhost','user2'@'localhost';
GRANT SELECT ON world。* TO'campart3';

帐户或角色名称的主机名部分(如果省略)默认为 '%'

通常,数据库管理员首先使用 CREATE USER 创建帐户并定义其非特权特征(如密码),是否使用安全连接以及对服务器资源的访问限制,然后使用它 GRANT 来定义其权限。 ALTER USER 可用于更改现有帐户的非特权。 例如:

创建用户'jeffrey'@'localhost'标识' password';
全部授予db1。*给'jeffrey'@'localhost';
GRANT SELECT ON db2.invoice TO'jeffrey'@'localhost';
更改用户'jeffrey'@'localhost'与MAX_QUERIES_PER_HOUR 90;

mysql 程序, 成功执行时 GRANT 响应 Query OK, 0 rows affected 要确定操作产生的特权,请使用 SHOW GRANTS 请参见 第13.7.6.21节“显示GRANTS语法”

重要

在某些情况下, GRANT 可以在历史文件中记录在服务器日志中或客户端上 ~/.mysql_history ,这意味着任何对该信息具有读访问权限的人都可以读取明文密码。 有关服务器日志发生的条件以及如何控制它的信息,请参见 第6.1.2.3节“密码和日志记录” 有关客户端日志记录的类似信息,请参见 第4.5.1.3节“mysql客户端日志记录”

GRANT 支持最长255个字符的主机名(MySQL 8.0.17之前的60个字符)。 用户名最多可包含32个字符。 数据库,表,列和例程名称最多可包含64个字符。

警告

请勿尝试通过更改 mysql.user 系统表 来更改用户名的允许长度 这样做会导致不可预测的行为,甚至可能使用户无法登录MySQL服务器 mysql 除非通过 第2.11节“升级MySQL”中 描述的过程,否则 切勿 以任何方式 更改 系统数据库 中表的结构

对象引用指南

GRANT 语句中的 几个对象 可以引用,但在许多情况下引用是可选的:帐户,角色,数据库,表,列和例程名称。 例如,如果 帐户名中的值 user_name host_name 值是合法的未加引号的标识符,则无需引用它。 然而,引号是必要指定 user_name 包含特殊字符(例如字符串 - ),或一个 host_name 包含字符串的特殊字符或通配符,如 % (例如 'test-user'@'%.com' )。 分别引用用户名和主机名。

要指定引用的值:

  • 引用数据库,表,列和例程名称作为标识符。

  • 引用用户名和主机名作为标识符或字符串。

  • 引用密码作为字符串。

有关字符串引用和标识符引用指南,请参见 第9.1.1节“字符串文字” 第9.2节“模式对象名称”

_ % 通配符在指定数据库名称时,允许 GRANT 格兰特在数据库级权限(报表 )。 这意味着,例如,要将 字符用作数据库名称的一部分,请 语句中 指定它 ,以防止用户能够访问与通配符模式匹配的其他数据库(例如, )。 GRANT ... ON db_name.* _ \_ GRANT GRANT ... ON `foo\_bar`.* TO ...

如果不使用数据库名称在数据库级别授予权限,但作为用于向某些其他对象(例如,表)或例程(例如 授予权限的限定符,则将 通配符视为普通字符。 GRANT ... ON db_name.tbl_name

帐户名称

语句中 user GRANT 表示该语句适用的MySQL帐户。 为了适应从任意主机授予用户权限,MySQL支持 user 在表单中 指定 'user_name'@'host_name'

您可以在主机名中指定通配符。 例如, 适用 域中的 任何主机 ,并 适用于 C类子网 中的任何主机 'user_name'@'%.example.com' user_name example.com 'user_name'@'198.51.100.%' user_name 198.51.100

简单形式 是同义词 'user_name' 'user_name'@'%'

MySQL不支持用户名中的通配符 要引用匿名用户,请使用以下 GRANT 语句 指定具有空用户名的帐户

GRANT ALL ON test。* TO''@'localhost'...;

在这种情况下,任何从本地主机连接匿名用户密码的用户都将被允许访问,并具有与匿名用户帐户关联的权限。

有关帐户名中的用户名和主机名值的其他信息,请参见 第6.2.4节“指定帐户名”

警告

如果您允许本地匿名用户连接到MySQL服务器,您还应该向所有本地用户授予权限 否则,匿名用户帐户 当指定的用户试图从本地机器上登录到MySQL服务器使用的系统表。 有关详细信息,请参见 第6.2.6节“访问控制,第1阶段:连接验证” 'user_name'@'localhost' localhost mysql.user

要确定此问题是否适用于您,请执行以下查询,该查询列出了所有匿名用户:

SELECT Host,User FROM mysql.user WHERE User ='';

要避免上述问题,请使用以下语句删除本地匿名用户帐户:

DROP USER''@'localhost';
MySQL支持的权限

下表总结了 priv_type 可以为 GRANT REVOKE 语句 指定 的允许的静态和动态 特权类型 ,以及可以授予每个特权的级别。 有关每个权限的其他信息,请参见 第6.2.2节“MySQL提供的权限” 有关静态和动态权限之间差异的信息,请参阅 静态与动态权限

表13.11 GRANT和REVOKE的允许静态权限

特权 意义和可授予级别
ALL [PRIVILEGES] 授予在指定的访问级别的所有权限,除了 GRANT OPTION PROXY
ALTER 启用 ALTER TABLE 级别:全局,数据库,表格。
ALTER ROUTINE 允许更改或删除存储的例程。 级别:全局,数据库,例程。
CREATE 启用数据库和表创建。 级别:全局,数据库,表格。
CREATE ROLE 启用角色创建。 等级:全球。
CREATE ROUTINE 启用存储的例程创建。 级别:全球,数据库。
CREATE TABLESPACE 启用要创建,更改或删除的表空间和日志文件组。 等级:全球。
CREATE TEMPORARY TABLES 启用 CREATE TEMPORARY TABLE 级别:全球,数据库。
CREATE USER 允许使用 CREATE USER DROP USER RENAME USER ,和 REVOKE ALL PRIVILEGES 等级:全球。
CREATE VIEW 启用要创建或更改的视图。 级别:全局,数据库,表格。
DELETE 启用 DELETE 级别:全局,数据库,表格。
DROP 启用要删除的数据库,表和视图。 级别:全局,数据库,表格。
DROP ROLE 启用要删除的角色。 等级:全球。
EVENT 启用事件计划程序的事件使用。 级别:全球,数据库。
EXECUTE 使用户能够执行存储的例程。 级别:全局,数据库,例程。
FILE 使用户能够使服务器读取或写入文件。 等级:全球。
GRANT OPTION 启用授予其他帐户或从其他帐户中删除的权限。 级别:全局,数据库,表,例程,代理。
INDEX 启用要创建或删除的索引。 级别:全局,数据库,表格。
INSERT 启用 INSERT 级别:全局,数据库,表格,列。
LOCK TABLES 允许使用 LOCK TABLES 您拥有该 SELECT 权限的表。 级别:全球,数据库。
PROCESS 使用户能够查看所有进程 SHOW PROCESSLIST 等级:全球。
PROXY 启用用户代理。 级别:从用户到用户。
REFERENCES 启用外键创建。 级别:全局,数据库,表格,列。
RELOAD 启用 FLUSH 操作。 等级:全球。
REPLICATION CLIENT 使用户可以询问主服务器或从服务器的位置。 等级:全球。
REPLICATION SLAVE 启用复制从属以从主服务器读取二进制日志事件。 等级:全球。
SELECT 启用 SELECT 级别:全局,数据库,表格,列。
SHOW DATABASES 启用 SHOW DATABASES 以显示所有数据库。 等级:全球。
SHOW VIEW 启用 SHOW CREATE VIEW 级别:全局,数据库,表格。
SHUTDOWN 启用 mysqladmin shutdown 等级:全球。
SUPER 能够使用如其他行政业务 CHANGE MASTER TO KILL PURGE BINARY LOGS SET GLOBAL ,和 中mysqladmin调试 命令。 等级:全球。
TRIGGER 启用触发操作。 级别:全局,数据库,表格。
UPDATE 启用 UPDATE 级别:全局,数据库,表格,列。
USAGE no privileges ”的 同义词

表13.12 GRANT和REVOKE的允许动态权限

特权 意义和可授予级别
APPLICATION_PASSWORD_ADMIN 启用双密码管理。 等级:全球。
AUDIT_ADMIN 启用审核日志配置。 等级:全球。
BACKUP_ADMIN 启用备份管理。 等级:全球。
BINLOG_ADMIN 启用二进制日志控制。 等级:全球。
BINLOG_ENCRYPTION_ADMIN 启用二进制日志加密的激活和取消激活。 等级:全球。
CONNECTION_ADMIN 启用连接限制/限制控制。 等级:全球。
ENCRYPTION_KEY_ADMIN 启用 InnoDB 键旋转。 等级:全球。
FIREWALL_ADMIN 启用防火墙规则管理,任何用户。 等级:全球。
FIREWALL_USER 启用防火墙规则管理,自我。 等级:全球。
GROUP_REPLICATION_ADMIN 启用组复制控制。 等级:全球。
PERSIST_RO_VARIABLES_ADMIN 启用持久性只读系统变量。 等级:全球。
REPLICATION_SLAVE_ADMIN 启用常规复制控制。 等级:全球。
RESOURCE_GROUP_ADMIN 启用资源组管理。 等级:全球。
RESOURCE_GROUP_USER 启用资源组管理。 等级:全球。
ROLE_ADMIN 允许授予或撤销角色,使用 WITH ADMIN OPTION 等级:全球。
SESSION_VARIABLES_ADMIN 启用设置受限会话系统变量。 等级:全球。
SET_USER_ID 启用设置非自我 DEFINER 值。 等级:全球。
SYSTEM_USER 将帐户指定为系统帐户。 等级:全球。
SYSTEM_VARIABLES_ADMIN 启用修改或持久化全局系统变量。 等级:全球。
TABLE_ENCRYPTION_ADMIN 启用覆盖默认加密设置。 等级:全球。
VERSION_TOKEN_ADMIN 允许使用版本标记UDF。 等级:全球。
XA_RECOVER_ADMIN 启用 XA RECOVER 执行。 等级:全球。

触发器与表关联。 要创建或删除触发器,您必须拥有 TRIGGER 该表 权限,而不是触发器。

GRANT 语句中, ALL [PRIVILEGES] PROXY 特权必须由其自身命名,不能与其他特权一起指定。 ALL [PRIVILEGES] 代表除了 GRANT OPTION PROXY 权限 之外授予权限的级别的所有 权限。

MySQL帐户信息存储在 mysql 系统数据库 的表中 有关其他详细信息,请参阅 第6.2节“访问控制和帐户管理” ,其中详细讨论了 mysql 系统数据库和访问控制系统。

如果授权表包含包含混合大小写数据库或表名的特权行,并且 lower_case_table_names 系统变量设置为非零值, REVOKE 则不能用于撤消这些特权。 有必要直接操纵授权表。 设置 GRANT 时不会创建此类行 lower_case_table_names ,但在设置该变量之前可能已创建此类行。该 lower_case_table_names 设置只能在服务器启动时配置。)

可以在多个级别授予权限,具体取决于 ON 子句 使用的语法 对于 REVOKE ,相同的 ON 语法指定要删除的权限。

对于全局,数据库,表和例程级别, GRANT ALL 仅分配您授予的级别上存在的权限。 例如, 是一个数据库级语句,因此它不会授予任何全局权限,例如 授予 不分配 特权。 GRANT ALL ON db_name.* FILE ALL GRANT OPTION PROXY

object_type 子句(如果存在)应指定为 TABLE FUNCTION 或者 PROCEDURE 当以下对象是表,存储函数或存储过程时。

用户为数据库,表,列或例程保存的权限是作为 OR 每个权限级别(包括全局级别)的帐户权限 的逻辑 相加形成的 由于在较低级别缺少该特权,因此无法拒绝在更高级别授予的特权。 例如,此语句 全局 授予 SELECT INSERT 权限:

GRANT SELECT,INSERT ON *。* TO u1;

全局授予的权限适用于所有数据库,表和列,即使未在任何较低级别授予。

从MySQL 8.0.16开始,如果 partial_revokes 启用 系统变量 ,则可以通过为特定数据库撤销在全局级别授予的权限来明确拒绝

GRANT SELECT,INSERT,UPDATE ON *。* TO u1;
REVOKE INSERT,UPDATE on db1。* FROM u1;

上述语句的结果是, SELECT 在全球范围适用于所有表格,而 INSERT UPDATE 全局应用除了在表中 db1 帐户访问权限 db1 是只读的。

有关权限检查过程的详细信息,请参见 第6.2.7节“访问控制,第2阶段:请求验证”

如果您对一个用户使用表,列或例程权限,则服务器会检查所有用户的表,列和例程权限,这会使MySQL慢一点。 同样,如果限制任何用户的查询,更新或连接数,则服务器必须监视这些值。

MySQL使您可以授予不存在的数据库或表的权限。 对于表,要授予的 CREATE 权限 必须包括 权限。 此行为是设计使然 ,旨在使数据库管理员能够为稍后要创建的数据库或表准备用户帐户和权限。

重要

删除数据库或表时,MySQL不会自动撤消任何权限 但是,如果删除例程,则会撤消为该例程授予的任何例程级权限。

全球特权

全局特权是管理的或适用于给定服务器上的所有数据库。 要分配全局权限,请使用 ON *.* 语法:

全部打开*。*给'someuser'@'somehost';
GRANT SELECT,INSERT ON *。*给'someuser'@'somehost';

CREATE TABLESPACE CREATE USER FILE PROCESS RELOAD REPLICATION CLIENT REPLICATION SLAVE SHOW DATABASES SHUTDOWN ,和 SUPER 静态特权是行政和只能在全球范围内授予。

动态权限都是全局的,只能全局授予。

其他权限可以在全球或更具体的级别授予。

GRANT OPTION 在全局级别授予 的效果 因静态和动态特权而异:

  • GRANT OPTION 授予任何静态全局特权适用于所有静态全局特权。

  • GRANT OPTION 授予任何动态权限仅适用于该动态权限。

GRANT ALL 在全局级别授予所有静态全局特权和所有当前注册的动态特权。 在执行该 GRANT 语句 之后注册的动态权限 不会追溯授予任何帐户。

MySQL将全局特权存储在 mysql.user 系统表中。

数据库权限

数据库权限适用于给定数据库中的所有对象。 要分配数据库级权限,请使用以下 语法: ON db_name.*

全部授予mydb。*给'someuser'@'somehost';
GRANT SELECT,INSERT ON mydb。* to'someuser'@'somehost';

如果使用 ON * 语法(而不是 ON *.* ),则在数据库级别为默认数据库分配权限。 如果没有默认数据库,则会发生错误。

CREATE DROP EVENT GRANT OPTION LOCK TABLES ,和 REFERENCES 权限可以在数据库级别指定。 还可以在数据库级别指定表或例程特权,在这种情况下,它们适用于数据库中的所有表或例程。

MySQL将数据库权限存储在 mysql.db 系统表中。

表权限

表权限适用于给定表中的所有列。 要分配表级权限,请使用以下 语法: ON db_name.tbl_name

在mydb.mytbl上给所有人''someuser'@'somehost';
GRANT SELECT,在mydb.mytbl上插入'someuser'@'somehost';

如果指定 tbl_name 而不是 db_name.tbl_name ,则该语句适用 tbl_name 于默认数据库。 如果没有默认数据库,则会发生错误。

容许 priv_type 在表级的值是 ALTER CREATE VIEW CREATE DELETE DROP GRANT OPTION INDEX INSERT REFERENCES SELECT SHOW VIEW TRIGGER ,和 UPDATE

表级权限适用于基表和视图。 CREATE TEMPORARY TABLE 即使表名匹配, 它们也不适用于使用创建 的表。 有关 TEMPORARY 表特权的 信息 ,请参见 第13.1.20.3节“CREATE TEMPORARY TABLE语法”

MySQL将表权限存储在 mysql.tables_priv 系统表中。

列权限

列权限适用于给定表中的单个列。 在列级别授予的每个权限必须后跟括号内的一列或多列。

GRANT SELECT(col1),INSERT(col1,col2)ON mydb.mytbl对'someuser'@'somehost';

可允许 priv_type 用于列(即,当你使用一个数值 column_list 条款)是 INSERT REFERENCES SELECT ,和 UPDATE

MySQL将列权限存储在 mysql.columns_priv 系统表中。

存储的例行权限

ALTER ROUTINE CREATE ROUTINE EXECUTE ,和 GRANT OPTION 权限适用于存储例程(过程和函数)。 它们可以在全局和数据库级别授予。 除此之外 CREATE ROUTINE ,可以在例程级别为单个例程授予这些特权。

在mydb上创建常规。*'someuser'@'somehost';
程序上的执行mydb.myproc对'someuser'@'somehost';

可允许 priv_type 在常规水平值 ALTER ROUTINE EXECUTE GRANT OPTION CREATE ROUTINE 不是例程级特权,因为您必须具有全局或数据库级别的特权才能首先创建例程。

MySQL在 mysql.procs_priv 系统表中 存储例程级特权

代理用户权限

PROXY 权限使一个用户成为另一个用户的代理。 代理用户冒充或取得代理用户的身份; 也就是说,它假定代理用户的特权。

授权'localuser'@'localhost'TO'externaluser'@'somehost';

PROXY 被授权,则必须在指定的唯一特权 GRANT 语句,唯一允许 WITH 选项 WITH GRANT OPTION

代理要求代理用户通过插件进行身份验证,该插件在代理用户连接时将代理用户的名称返回给服务器,并且代理用户具有代理用户的 PROXY 权限。 有关详细信息和示例,请参见 第6.2.18节“代理用户”

MySQL将代理权限存储在 mysql.proxies_priv 系统表中。

授予角色

GRANT 没有 ON 子句的 语法 授予角色而不是个人特权。 角色是命名的特权集合; 请参见 第6.2.10节“使用角色” 例如:

GRANT'rort1','role2'TO'user1'@'localhost','user2'@'localhost';

必须存在要授予的每个角色,以及要授予它的每个用户帐户或角色。 从MySQL 8.0.16开始,无法向匿名用户授予角色。

授予角色不会自动导致角色处于活动状态。 有关角色激活和失活的信息,请参阅 激活角色

授予角色需要这些权限:

  • 如果您拥有 ROLE_ADMIN 拥有该 SUPER 权限,则可以向用户或角色授予或撤消任何角色。

  • 如果您被授予 GRANT 包含该 WITH ADMIN OPTION 子句 语句 的角色 ,则您可以将该角色授予其他用户或角色,或者从其他用户或角色撤消该角色,只要该角色在您随后授予时处于活动状态或撤销它。 这包括使用 WITH ADMIN OPTION 自身 的能力

  • 要授予具有该 SYSTEM_USER 权限 的角色 ,您必须具有该 SYSTEM_USER 权限。

可以使用创建循环引用 GRANT 例如:

创建用户'u1','u2';
CREATE ROLE'r1','r2';

授予'u1'给'u1';  - 简单循环:u1 => u1
GRANT'r1'TO'r1';  - 简单循环:r1 => r1

GRANT'r2'到'u2';
GRANT'u2'to'r2';  - 混合用户/角色循环:u2 => r2 => u2

允许使用循环授权,但不向授予者添加新的特权或角色,因为用户或角色已具有其特权和角色。

AS 条款和权限限制

从MySQL 8.0.16开始, GRANT 有一个 子句指定有关用于语句执行的特权上下文的其他信息。 此语法在SQL级别可见,但其主要目的是通过使这些限制出现在二进制日志中,在部分撤销所强制的所有节点上实现统一复制。 有关部分撤消的信息,请参见 第6.2.12节“使用部分撤消的权限限制” AS user [WITH ROLE]

指定WHERE子句,语句的执行考虑到与指定用户相关联的任何权限限制,其中包括指定的所有角色 ,如果存在的话。 结果是语句实际授予的权限可能相对于指定的权限减少。 AS user WITH ROLE

这些条件适用于该 条款: AS user

  • AS 仅当命名 user 具有权限限制(这意味着 partial_revokes 启用 系统变量) 时才有效

  • 如果 WITH ROLE 给出,则必须将所有命名的角色授予named user

  • 命名 user 应指定为MySQL账户 当前用户可以与 执行用户想要 使用可能与当前会话中活动的角色不同的一组角色 执行的情况 一起命名 'user_name'@'host_name' CURRENT_USER CURRENT_USER() WITH ROLE GRANT

  • AS 不能用于获取执行 GRANT 语句 的用户所拥有的权限 执行用户必须至少具有要授予的权限,但该 AS 子句只能限制授予的权限,而不能升级它们。

  • 对于要授予的权限, AS 无法指定具有比执行 GRANT 语句 的用户更多权限(更少限制)的用户/角色组合 AS 用户/角色组合允许具有比执行用户更多权限,但前提是该语句不授予这些额外的权限。

  • AS 仅支持授予全局权限( ON *.* )。

  • AS PROXY 资助 不支持

以下示例说明了该 AS 子句 的效果 创建 u1 具有某些全局权限 的用户 ,以及对这些权限的限制:

创建用户u1;
GRANT SELECT,INSERT,UPDATE,DELETE ON *。* TO u1;
REVOKE INSERT,更新schema1。* FROM u1;
REVOKE SELECT在schema2。* FROM u1;

还要创建一个角色 r1 来解除某些权限限制并将角色授予 u1

创造角色r1;
GRANT INSERT ON schema1。* TO r1;
GRANT SELECT ON schema2。* TO r1;
GRANT r1 TO u1;

现在,使用一个没有自己的权限限制的帐户,向多个用户授予相同的全局权限集,但每个 AS 权限都 受到该 子句 强加的不同限制 ,并检查实际授予的权限。

  • GRANT 此处 语句没有 AS 子句,因此授予的权限正是指定的权限:

    mysql> CREATE USER u2;
    mysql> GRANT SELECT, INSERT, UPDATE ON *.* TO u2;
    mysql>SHOW GRANTS FOR u2;
    + ------------------------------------------------- +
    | u2 @%|的补助金
    + ------------------------------------------------- +
    | GRANT SELECT,INSERT,UPDATE ON *。* to`u2` @`%`|
    + ------------------------------------------------- +
    
  • GRANT 此处 语句有一个 AS 子句,因此授予的权限是指定的权限,但具有应用的限制 u1

    mysql> CREATE USER u3;
    mysql> GRANT SELECT, INSERT, UPDATE ON *.* TO u3 AS u1;
    mysql>SHOW GRANTS FOR u3;
    + ------------------------------------------------- --- +
    | u3 @%|的补助金
    + ------------------------------------------------- --- +
    | GRANT SELECT,INSERT,UPDATE ON *。* to`u3` @`%`|
    | REVOKE INSERT,更新`schema1`。* FROM`u3` @`%`|
    | REVOKE SELECT在`schema2`。* FROM`u3` @`%`|
    + ------------------------------------------------- --- +
    

    如前所述,该 AS 子句只能添加权限限制; 它不能升级特权。 因此,虽然 u1 具有 DELETE 权限 ,但 由于该语句未指定授予,因此未包含在授予的权限中 DELETE

  • 此处声明 AS 子句 GRANT 使角色 r1 处于活动状态 u1 这个角色取消了一些限制 u1 因此,授予的权限有一些限制,但不会像以前的 GRANT 声明 那么多

    mysql> CREATE USER u4;
    mysql> GRANT SELECT, INSERT, UPDATE ON *.* TO u4 AS u1 WITH ROLE r1;
    mysql>SHOW GRANTS FOR u4;
    + ------------------------------------------------- +
    | u4 @%|的补助金
    + ------------------------------------------------- +
    | GRANT SELECT,INSERT,UPDATE ON *。* to`u4` @`%`|
    | REVOKE更新`schema1`。* FROM`u4` @`%`|
    + ------------------------------------------------- +
    

如果 GRANT 语句包含 子句,则忽略对执行语句的用户的权限限制(而不是像没有 子句时那样应用)。 AS user AS

其他账户特征

optional WITH 子句用于使用户能够向其他用户授予权限。 WITH GRANT OPTION 子句使用户能够向其他用户提供用户在指定权限级别拥有的任何权限。

要在 GRANT OPTION 不更改其权限的情况下 权限 授予 帐户,请执行以下操作:

授予使用*。*给'someuser'@'somehost'WITH GRANT OPTION;

请注意您授予谁的 GRANT OPTION 权限,因为具有不同权限的两个用户可能能够组合权限!

您不能授予其他用户您自己没有的权限; GRANT OPTION 权限使您只能分配您自己拥有的权限。

请注意,当您授予用户 GRANT OPTION 特定权限级别的权限时,该用户在该级别拥有(或可能在将来获得)的任何权限也可由该用户授予其他用户。 假设您授予用户 INSERT 对数据库 权限。 如果您随后 SELECT 在数据库上 授予 权限并指定 WITH GRANT OPTION ,则该用户不仅可以向其他用户提供 SELECT 权限,还可以 INSERT 如果你再授予 UPDATE 权限的数据库用户,用户可以授予 INSERT SELECT UPDATE

对于非管理用户,不应 ALTER 全局或 mysql 系统数据库 授予 权限 如果这样做,用户可以尝试通过重命名表来破坏权限系统!

有关与特定权限相关的安全风险的其他信息,请参见 第6.2.2节“MySQL提供的权限”

MySQL和GRANT的标准SQL版本

MySQL和标准SQL版本之间的最大区别 GRANT 是:

  • MySQL将权限与主机名和用户名的组合相关联,而不是仅与用户名相关联。

  • 标准SQL没有全局或数据库级特权,也不支持MySQL支持的所有特权类型。

  • MySQL不支持标准SQL UNDER 权限。

  • 标准SQL权限以分层方式构建。 如果删除用户,则会撤消已授予用户的所有权限。 如果您使用,在MySQL中也是如此 DROP USER 请参见 第13.7.1.5节“DROP USER语法”

  • 在标准SQL中,删除表时,将撤消表的所有权限。 在标准SQL中,撤消权限时,也会撤消基于该权限授予的所有权限。 在MySQL中,可以使用 DROP USER REVOKE 语句 删除权限

  • 在MySQL中,可以 INSERT 仅对表中的某些列 具有 权限。 在这种情况下,您仍然可以 INSERT 在表上 执行 语句,前提是您只为您拥有该 INSERT 权限的 列插入值 如果未启用严格SQL模式,则省略的列将设置为其隐式默认值。 在严格模式下,如果任何省略的列没有默认值,则拒绝该语句。 (标准SQL要求您拥有 INSERT 所有列 权限。)有关严​​格SQL模式和隐式默认值的信息,请参阅 第5.1.11节“服务器SQL模式” 第11.7节“数据类型默认值”

13.7.1.7 RENAME USER语法

重命名用户old_usernew_user
    [,old_userTO new_user] ......

RENAME USER 语句重命名现有的MySQL帐户。 对于不存在的旧帐户或已存在的新帐户,会出错。

要使用 RENAME USER ,您必须具有全局 CREATE USER 特权或 系统数据库 UPDATE 特权 mysql read_only 启用了系统变量, RENAME USER 另外需要 CONNECTION_ADMIN SUPER 特权。

每个帐户名称使用 第6.2.4节“指定帐户名称”中 所述的格式 例如:

重命名用户'jeffrey'@'localhost'TO'jeff'@'127.0.0.1';

帐户名的主机名部分(如果省略)默认为 '%'

RENAME USER 导致旧用户持有的权限是新用户持有的权限。 但是, RENAME USER 不会自动删除或使旧用户创建的数据库或对象无效。 这包括存储的程序或视图, DEFINER 属性为旧用户命名。 如果在定义的安全性上下文中执行,则尝试访问此类对象可能会产生错误。 (有关安全上下文的信息,请参见 第24.6节“存储对象访问控制” 。)

权限更改将在 第6.2.13节 “特权更改生效时”中指示生效

13.7.1.8 REVOKE语法

REVOKE
     priv_type[(column_list)]
      [,priv_type[(column_list)]] ......
    ON [ object_type] priv_level
    FROM user_or_role[,user_or_role] ......

撤消所有[特权],授予选项权限
    FROM user_or_role[,user_or_role] ......

REVOKE PROXY user_or_role
    来自user_or_role[,user_or_role] ......

REVOKE role[,role] ......
    FROM user_or_role[,user_or_role] ......

user_or_role:{
     user
  |role
}

user
    (参见第6.2.4节“指定帐户名”

role
    (请参见第6.2.5节“指定角色名称”)

REVOKE 语句使系统管理员可以撤消权限和角色,这些权限和角色可以从用户帐户和角色中撤消。

有关角色的信息,请参见 第6.2.10节“使用角色”

read_only 系统变量被启用, REVOKE 需要 CONNECTION_ADMIN SUPER 特权除了在下面的讨论中描述的任何其它所需的特权。

REVOKE 要么为所有命名用户和角色成功,要么回滚,如果发生任何错误,则无效。 只有当所有命名用户和角色成功时,该语句才会写入二进制日志。

每个帐户名称使用 第6.2.4节“指定帐户名称”中 所述的格式 每个角色名称使用 第6.2.5节“指定角色名称”中 描述的格式 例如:

REVOKE INSERT ON *。* FROM'jeffrey'@'localhost';
REVOKE'rort1','role2'FROM'user1'@'localhost','user2'@'localhost';
REVOKE SELECT ON world。* FROM'rob3';

帐户或角色名称的主机名部分(如果省略)默认为 '%'

有关在哪些特权存在的水平,允许的细节 priv_type priv_level object_type 值,以及指定用户名和密码的语法,请参阅 第13.7.1.6,“GRANT和REVOKE语法”

要使用第一种 REVOKE 语法,您必须具有该 GRANT OPTION 权限,并且必须具有要撤消的权限。

要撤消所有权限,请使用第二种语法,该语法将删除指定用户或角色的所有全局,数据库,表,列和例程权限:

改善所有特权,授予选择权
  FROM user_or_role[,user_or_role] ......

REVOKE ALL PRIVILEGES, GRANT OPTION 不会撤销任何角色。

要使用此 REVOKE 语法,您必须具有全局 CREATE USER 特权或 系统数据库 UPDATE 特权 mysql

REVOKE 关键字后跟一个或多个角色名称 的语法 采用一个 FROM 子句,指示从中撤消角色的一个或多个用户或角色。

mandatory_roles 系统变量值中 命名的角色 无法撤消。

撤消的角色会立即影响撤消该角色的任何用户帐户,以便在该帐户的任何当前会话中,为下一个执行的语句调整其权限。

撤消角色会撤消角色本身,而不是撤消角色所代表的权限。 如果为帐户授予包含给定权限的角色,并且还明确授予该权限或包含该权限的其他角色,则在撤消第一个角色后,该帐户仍会被授予该权限。 例如,如果一个帐户被授予两个包含的角色 SELECT ,则该帐户仍可以在撤消任一角色后进行选择。

REVOKE ALL ON *.* (在全局级别)撤消所有授予的静态全局特权和所有授予的动态特权。

必须存在要撤消特权和角色的用户帐户和角色,但当前不需要授予要撤消的角色。

REVOKE 删除权限,但不删除 mysql.user 系统表条目。 要完全删除用户帐户,请使用 DROP USER 请参见 第13.7.1.5节“DROP USER语法”

如果授权表包含包含混合大小写数据库或表名的特权行,并且 lower_case_table_names 系统变量设置为非零值, REVOKE 则不能用于撤消这些特权。 有必要直接操纵授权表。 设置 GRANT 时不会创建此类行 lower_case_table_names ,但在设置变量之前可能已创建此类。 lower_case_table_names 只能在初始化服务器时配置 设置。)

当从 mysql 程序 成功执行时 REVOKE 响应 Query OK, 0 rows affected 要确定操作后剩余的权限,请使用 SHOW GRANTS 请参见 第13.7.6.21节“显示GRANTS语法”

13.7.1.9 SET DEFAULT ROLE语法

设定默认角色
    {无| 所有| role[,role] ......}
    TO user[,user] ......

对于 user 紧跟在 TO 关键字 之后的 每个 命名 ,此语句定义当用户连接到服务器并进行身份验证时,或者用户 SET ROLE DEFAULT 在会话期间 执行 语句 时,哪些角色变为活动状态

SET DEFAULT ROLE 是替代语法 ALTER USER ... DEFAULT ROLE (参见 第13.7.1.1节“ALTER USER语法” )。 但是, ALTER USER 可以仅为单个用户 SET DEFAULT ROLE 设置默认值 ,而 可以为多个用户设置默认值。 另一方面,您可以指定 语句 CURRENT_USER 的用户名 ALTER USER ,而不能用于 SET DEFAULT ROLE

SET DEFAULT ROLE 需要这些特权:

  • 为其他用户设置默认角色需要全局 CREATE USER 权限或 系统表 UPDATE 权限 mysql.default_roles

  • 为自己设置默认角色不需要特殊权限,只要您希望将您想要的角色授予您。

每个角色名称使用 第6.2.5节“指定角色名称”中 描述的格式 例如:

SET DEFAULT ROLE管理员,开发人员TO'joe'@'10.0.0.1';

角色名称的主机名部分(如果省略)默认为 '%'

DEFAULT ROLE 关键字 后面的子句 允许这些值:

  • NONE :将默认值设置为 NONE (无角色)。

  • ALL :将默认值设置为授予该帐户的所有角色。

  • role [, role ] ... :将默认值设置为命名角色,该角色必须存在并在执行时授予帐户 SET DEFAULT ROLE

注意

SET DEFAULT ROLE 并且 SET ROLE DEFAULT 是不同的陈述:

有关角色使用示例,请参见 第6.2.10节“使用角色”

13.7.1.10 SET PASSWORD语法

设置密码[FOR user] =' auth_string'
    [REPLACE' current_auth_string']
    [保留当前密码]

SET PASSWORD 语句为MySQL用户帐户分配密码。 它还可能包含一个password-verification子句,用于指定要替换的帐户当前密码,以及一个管理帐户是否具有二级密码的子句。 并且 每个代表一个明文(未加密)密码。 'auth_string' 'current_auth_string'

注意

密码验证次密码条款仅适用于内部存储凭据的账户 mysql.user 系统表( mysql_native_password sha256_password ,或 caching_sha2_password )。 对于使用对外部凭据系统执行身份验证的插件的帐户,还必须在该系统外部处理密码管理。

子句从MySQL 8.0.13开始提供。 如果给出: REPLACE 'current_auth_string'

  • REPLACE 指定要替换的帐户当前密码,作为明文(未加密)字符串。

  • 如果需要对帐户进行密码更改以指定当前密码,则必须提供该条款,作为尝试进行更改的用户实际知道当前密码的验证。

  • 如果帐户的密码更改可能但不需要指定当前密码,则该子句是可选的。

  • 如果给出了该子句但该语句与当前密码不匹配,则该语句失败,即使该子句是可选的。

  • REPLACE 只有在更改当前用户的帐户密码时才能指定。

有关通过指定当前密码进行密码验证的更多信息,请参见 第6.2.15节“密码管理”

RETAIN CURRENT PASSWORD 子句实现双密码功能,从MySQL 8.0.14开始提供。 如果给出:

  • RETAIN CURRENT PASSWORD 保留帐户当前密码作为其辅助密码,替换任何现有的二级密码。 新密码将成为主密码,但客户端可以使用该帐户使用主密码或辅助密码连接到服务器。 (例外:如果 SET PASSWORD 语句 指定的新密码 为空,则辅助密码也会变为空,即使 RETAIN CURRENT PASSWORD 已给出。)

  • 如果 RETAIN CURRENT PASSWORD 为具有空主密码的帐户 指定 ,则该语句将失败。

  • 如果帐户具有辅助密码并且您在未指定 RETAIN CURRENT PASSWORD 情况下更改其主密码 ,则辅助密码将保持不变。

有关使用双密码的更多信息,请参见 第6.2.15节“密码管理”

注意

语法是帐户更改的首选语句 而不是使用 语法 ,包括分配密码。 例如: SET PASSWORD ... = 'auth_string' ALTER USER

更改用户user身份' auth_string';
重要

在某些情况下, SET PASSWORD 可以在历史文件中记录在服务器日志中或客户端上 ~/.mysql_history ,这意味着任何对该信息具有读访问权限的人都可以读取明文密码。 有关服务器日志发生的条件以及如何控制它的信息,请参见 第6.1.2.3节“密码和日志记录” 有关客户端日志记录的类似信息,请参见 第4.5.1.3节“mysql客户端日志记录”

SET PASSWORD 可以使用或不使用 FOR 明确命名用户帐户 子句:

  • 使用 子句,该语句设置指定帐户的密码,该密码必须存在: FOR user

    为'jeffrey'设置密码@'localhost'=' auth_string';
    
  • 如果没有 子句,该语句将为当前用户设置密码: FOR user

    SET PASSWORD =' auth_string';
    

    使用非匿名帐户连接到服务器的任何客户端都可以更改该帐户的密码。 (特别是,您可以更改自己的密码。)要查看服务器对您进行身份验证的帐户,请调用以下 CURRENT_USER() 函数:

    SELECT CURRENT_USER();
    

如果 给出 子句,则帐户名称使用 第6.2.4节“指定帐户名称”中 所述的格式 例如: FOR user

SET PASSWORD FOR'bob'@'%.example.org'=' auth_string';

帐户名的主机名部分(如果省略)默认为 '%'

SET PASSWORD 将字符串解释为明文字符串,将其传递给与帐户关联的身份验证插件,并将插件返回的结果存储在 mysql.user 系统表 的帐户行中 (该插件有机会将值散列为它所期望的加密格式。插件可以使用指定的值,在这种情况下不会发生散列。)

为指定帐户(带 FOR 子句) 设置密码 需要 系统数据库 UPDATE 权限 mysql 为自己设置密码(对于没有 FOR 子句 的非匿名帐户 )不需要特殊权限。

修改辅助密码的语句需要以下权限:

  • APPLICATION_PASSWORD_ADMIN 权限才能使用 RETAIN CURRENT PASSWORD 的条款 SET PASSWORD 适用于您自己的账户报表。 由于大多数用户只需要一个密码,因此需要使用该权限来操作您自己的二级密码。

  • 如果允许某个帐户操作所有帐户的辅助密码,则应授予其 CREATE USER 权限,而不是 APPLICATION_PASSWORD_ADMIN

read_only 系统变量被启用, SET PASSWORD 要求 CONNECTION_ADMIN SUPER 特权,除了所需的其他特权。

有关设置密码和身份验证插件的其他信息,请参见 第6.2.14节“分配帐户密码” 第6.2.17节“可插入身份验证”

13.7.1.11 SET ROLE语法

SET ROLE {
    默认
  | 没有
  | 所有
  | 除了role[,role]之外......
  | role[,role] ......
}

SET ROLE 通过指定其授予的哪些角色处于活动状态来修改当前用户在当前会话中的有效权限。 授予的角色包括明确授予用户的角色和 mandatory_roles 系统变量值中 指定的角色

例子:

设定角色默认;
设置角色'role1','role2';
SET ROLE ALL;
SET ROLE ALL除'role1','role2'之外;

每个角色名称使用 第6.2.5节“指定角色名称”中 描述的格式 角色名称的主机名部分(如果省略)默认为 '%'

直接授予用户(而不是通过角色)的权限不受活动角色更改的影响。

该语句允许这些角色说明符:

  • DEFAULT :激活帐户默认角色。 默认角色是指定的角色 SET DEFAULT ROLE

    当用户连接到服务器并成功进行身份验证时,服务器会确定要激活哪些角色作为默认角色。 如果 activate_all_roles_on_login 启用 系统变量,则服务器将激活所有已授予的角色。 否则,服务器 SET ROLE DEFAULT 隐式 执行 服务器仅激活可以激活的默认角色。 对于无法激活的默认角色,服务器会将警告写入其错误日志,但客户端不会收到警告。

    如果用户 SET ROLE DEFAULT 在会话期间 执行 ,则如果无法激活任何默认角色(例如,如果它不存在或未授予用户),则会发生错误。 在这种情况下,当前活动角色不会更改。

  • NONE :将活动角色设置为 NONE (无活动角色)。

  • ALL :激活授予该帐户的所有角色。

  • ALL EXCEPT role [, role ] ... :激活授予帐户的所有角色,但命名的角色除外。 指定的角色不需要存在或被授予该帐户。

  • role [, role ] ... :激活必须授予帐户的指定角色。

注意

SET DEFAULT ROLE 并且 SET ROLE DEFAULT 是不同的陈述:

有关角色使用示例,请参见 第6.2.10节“使用角色”

13.7.2资源组管理声明

MySQL支持资源组的创建和管理,并允许将服务器内运行的线程分配给特定组,以便线程根据组可用的资源执行。 本节介绍可用于资源组管理的SQL语句。 有关资源组功能的一般讨论,请参见 第8.12.5节“资源组”

13.7.2.1 ALTER RESOURCE GROUP语法

ALTER RESOURCE GROUP group_name
    [VCPU [=] vcpu_spec[,vcpu_spec] ...]
    [THREAD_PRIORITY [=] N]
    [ENABLE | DISABLE [FORCE]]

vcpu_spec:{ N| M- N}

ALTER RESOURCE GROUP 用于资源组管理(请参见 第8.12.5节“资源组” )。 此语句更改现有资源组的可修改属性。 它需要 RESOURCE_GROUP_ADMIN 特权。

group_name 标识要更改的资源组。 如果该组不存在,则会发生错误。

可以使用修改CPU亲缘关系,优先级以及是否启用组的属性 ALTER RESOURCE GROUP 这些属性的描述方式与描述的相同 CREATE RESOURCE GROUP (参见 第13.7.2.2节“CREATE RESOURCE GROUP语法” )。 仅更改指定的属性。 未指定的属性保留其当前值。

FORCE 改性剂使用 DISABLE 如果资源组分配了任何线程,它将确定语句行为:

  • 如果 FORCE 未给出,则组中的现有线程将继续运行,直到它们终止,但无法将新线程分配给该组。

  • 如果 FORCE 给定,则组中的现有线程将移动到其各自的默认组(系统线程 SYS_default ,用户线程 USR_default )。

名称和类型属性在组创建时设置,之后不能修改 ALTER RESOURCE GROUP

例子:

  • 更改组CPU亲和性:

    ALTER RESOURCE GROUP rg1 VCPU = 0-63;
    
  • 更改组线程优先级:

    ALTER RESOURCE GROUP rg2 THREAD_PRIORITY = 5;
    
  • 禁用组,将分配给它的任何线程移动到默认组:

    ALTER RESOURCE GROUP rg3 DISABLE FORCE;
    

资源组管理是发生它的服务器的本地管理。 ALTER RESOURCE GROUP 语句不会写入二进制日志,也不会被复制。

13.7.2.2 CREATE RESOURCE GROUP语法

创建资源组 group_name
    TYPE = {SYSTEM | USER}
    [VCPU [=] vcpu_spec[,vcpu_spec] ......]
    [THREAD_PRIORITY [=] N]
    [ENABLE | DISABLE]

vcpu_spec:{ N| M- N}

CREATE RESOURCE GROUP 用于资源组管理(请参见 第8.12.5节“资源组” )。 此语句创建新资源组并分配其初始属性值。 它需要 RESOURCE_GROUP_ADMIN 特权。

group_name 标识要创建的资源组。 如果该组已存在,则会发生错误。

TYPE 属性是必需的。 它应该是 SYSTEM 系统资源组, USER 用于用户资源组。 组类型会影响允许的 THREAD_PRIORITY 值,如稍后所述。

VCPU 属性表示CPU亲和性; 也就是说,组可以使用的虚拟CPU集合:

  • 如果 VCPU 未给出,则资源组没有CPU关联,并且可以使用所有可用的CPU。

  • 如果 VCPU 给定,则属性值是逗号分隔的CPU编号或范围的列表:

    • 每个数字必须是一个整数,范围从0到CPU数量 - 1.例如,在具有64个CPU的系统上,数字的范围可以是0到63。

    • 范围以 M - N M 小于或等于 的形式给出, N 两个数字都在CPU范围内。

    • 如果CPU编号是超出允许范围的整数或不是整数,则会发生错误。

示例 VCPU 说明符(这些都是等效的):

VCPU = 0,1,2,3,9,10
VCPU = 0-3,9-10
VCPU = 9,10,0-3
VCPU = 0,10,1,9,3,2

THREAD_PRIORITY 属性指示分配给组的线程的优先级:

  • 如果 THREAD_PRIORITY 未给出,则默认优先级为0。

  • 如果 THREAD_PRIORITY 给定,则属性值必须在-20(最高优先级)到19(最低优先级)的范围内。 系统资源组的优先级必须介于-20到0之间。用户资源组的优先级必须介于0到19之间。对系统和用户组使用不同的范围可确保用户线程永远不会更高优先级高于系统线程。

ENABLE DISABLE 指定最初启用或禁用资源组。 如果未指定,则默认情况下启用该组。 禁用的组不能分配线程。

例子:

  • 创建具有单个CPU且优先级最低的已启用用户组:

    CREATE RESOURCE GROUP rg1
      TYPE = USER
      VCPU = 0
      THREAD_PRIORITY = 19;
    
  • 创建一个没有CPU关联(可以使用所有CPU)和最高优先级的已禁用系统组:

    CREATE RESOURCE GROUP rg2
      TYPE = SYSTEM
      THREAD_PRIORITY = -20
      禁用;
    

资源组管理是发生它的服务器的本地管理。 CREATE RESOURCE GROUP 语句不会写入二进制日志,也不会被复制。

13.7.2.3 DROP RESOURCE GROUP语法

DROP RESOURCE GROUP group_name[FORCE]

DROP RESOURCE GROUP 用于资源组管理(请参见 第8.12.5节“资源组” )。 此语句删除资源组。 它需要 RESOURCE_GROUP_ADMIN 特权。

group_name 标识要删除的资源组。 如果该组不存在,则会发生错误。

FORCE 修改决定声明的行为,如果资源组具有分配给它的任何线程:

  • 如果 FORCE 未给出并且任何线程都分配给该组,则会发生错误。

  • 如果 FORCE 给定,则组中的现有线程将移动到其各自的默认组(系统线程 SYS_default ,用户线程 USR_default )。

例子:

  • 删除组,如果组包含任何线程,则失败:

    DROP RESOURCE GROUP rg1;
    
  • 删除组并将现有线程移动到默认组:

    DROP RESOURCE GROUP rg2 FORCE;
    

资源组管理是发生它的服务器的本地管理。 DROP RESOURCE GROUP 语句不会写入二进制日志,也不会被复制。

13.7.2.4 SET RESOURCE GROUP语法

SET RESOURCE GROUP group_name
    [FOR thread_id[,thread_id] ...]

SET RESOURCE GROUP 用于资源组管理(请参见 第8.12.5节“资源组” )。 此语句将线程分配给资源组。 它需要 RESOURCE_GROUP_ADMIN RESOURCE_GROUP_USER 特权。

group_name 标识要分配的资源组。 任何 thread_id 值都表示要分配给组的线程。 可以从Performance Schema threads 表中 确定线程ID 如果资源组或任何命名的线程ID不存在,则会发生错误。

如果没有 FOR 子句,则语句将会话的当前线程分配给资源组。

使用 FOR 命名线程ID 子句,该语句将这些线程分配给资源组。

对于将系统线程分配给用户资源组或将用户线程分配给系统资源组的尝试,会发出警告。

例子:

  • 将当前会话线程分配给组:

    SET RESOURCE GROUP rg1;
    
  • 将命名线程分配给组:

    SET RESOURCE GROUP rg2 FOR 14,18,4;
    

资源组管理是发生它的服务器的本地管理。 SET RESOURCE GROUP 语句不会写入二进制日志,也不会被复制。

另一种方法 SET RESOURCE GROUP RESOURCE_GROUP 优化器提示,它将单个语句分配给资源组。 请参见 第8.9.3节“优化程序提示”

13.7.3表维护声明

13.7.3.1 ANALYZE TABLE语法

分析[NO_WRITE_TO_BINLOG | 本地]tbl_name[,tbl_name] ......

分析[NO_WRITE_TO_BINLOG | 本地]
    TABLE tbl_name
    UPDATE HISTOGRAM ON col_name[,col_name] ...
        [带N桶]

分析[NO_WRITE_TO_BINLOG | 本地]tbl_name
    DROP HISTOGRAM ON col_name[,col_name] ...

ANALYZE TABLE 生成表统计信息:

  • ANALYZE TABLE 如果没有任何一个 HISTOGRAM 子句执行密钥分发分析并存储指定表或表的分布。 对于 MyISAM 表, ANALYZE TABLE 关键分布分析相当于使用 myisamchk --analyze

  • ANALYZE TABLE with UPDATE HISTOGRAM 子句为命名表列生成直方图统计信息,并将它们存储在数据字典中。 此语法只允许使用一个表名。

  • ANALYZE TABLE with DROP HISTOGRAM 子句从数据字典中删除指定表列的直方图统计信息。 此语法只允许使用一个表名。

注意

如果 innodb_read_only 启用 系统变量,则 ANALYZE TABLE 可能会失败,因为它无法更新数据字典中使用的统计表 InnoDB 对于 ANALYZE TABLE 更新密钥分发的操作,即使操作更新表本身(例如,如果它是 MyISAM 表) ,也可能发生故障 要获取更新的分布统计信息,请设置 information_schema_stats_expiry=0

此语句需要 表的权限 SELECT INSERT 特权。

ANALYZE TABLE 有工作 InnoDB NDB MyISAM 表。 它不适用于视图。

ANALYZE TABLE 分区表支持,您可以 ALTER TABLE ... ANALYZE PARTITION 用来分析一个或多个分区; 有关更多信息,请参见 第13.1.9节“ALTER TABLE语法” 第23.3.4节“分区维护”

在分析过程中,表格被锁定,读取锁定为 InnoDB MyISAM

默认情况下,服务器将 ANALYZE TABLE 语句 写入 二进制日志,以便它们复制到复制从属服务器。 要禁止记录,请指定可选 NO_WRITE_TO_BINLOG 关键字或其别名 LOCAL

分析表输出

ANALYZE TABLE 返回结果集,其中包含下表中显示的列。

Table 表名
Op analyze 要么 histogram
Msg_type status error info note ,或 warning
Msg_text 信息性消息
关键分布分析

ANALYZE TABLE 如果没有任何一个 HISTOGRAM 子句执行密钥分发分析并存储一个或多个表的分布。 任何现有的直方图统计数据都不受影响。

如果自上次密钥分发分析以来表未更改,则不再对该表进行分析。

MySQL使用存储的密钥分发来决定表连接的顺序,以便在常量之外的连接上进行连接。 此外,在决定用于查询中的特定表的索引时,可以使用密钥分发。

有关密钥分发分析如何工作的更多信息 InnoDB ,请参见 第15.8.10.1节“配置持久优化器统计信息参数” 第15.8.10.3节“估算InnoDB表的分析表复杂度” 另请参见 第15.6.1.6节“InnoDB表的限制” 特别是,当您启用该 innodb_stats_persistent 选项时,必须 ANALYZE TABLE 在将大量数据加载到 InnoDB 表中或为其创建新索引后运行。

要检查存储的密钥分发基数,请使用 SHOW INDEX 语句或 INFORMATION_SCHEMA STATISTICS 表。 请参见 第13.7.6.22节“SHOW INDEX语法” 第25.26节“INFORMATION_SCHEMA STATISTICS表”

直方图统计分析

ANALYZE TABLE 使用 HISTOGRAM 子句可以管理表列值的直方图统计信息。 有关直方图统计信息,请参见 第8.9.6节“优化程序统计信息”

这些直方图操作可用:

  • ANALYZE TABLE with UPDATE HISTOGRAM 子句为命名表列生成直方图统计信息,并将它们存储在数据字典中。 此语法只允许使用一个表名。

    可选 子句指定直方图的桶数。 必须是1到1024之间的整数。如果省略该子句,则桶数为100。 WITH N BUCKETS N

  • ANALYZE TABLE with DROP HISTOGRAM 子句从数据字典中删除指定表列的直方图统计信息。 此语法只允许使用一个表名。

存储的直方图管理语句仅影响指定的列。 请考虑以下陈述:

分析表t更新c1,c2,c3上有10个桶的直方图;
分析表t更新c1,c3上有10个桶的直方图;
在c2上分析表t DROP HISTOGRAM;

第一条语句将更新列的直方图 c1 c2 以及 c3 ,替换任何现有的直方图那些列。 第二条语句更新直方图 c1 c3 ,离开 c2 直方图不受影响。 第三个语句删除了直方图 c2 ,留下 了直方图 c1 c3 不受影响 的直方图

加密表不支持直方图生成(以避免在统计信息中公开数据)或 TEMPORARY 表。

直方图生成适用于除几何类型(空间数据)和之外的所有数据类型的列 JSON

可以为存储的和虚拟生成的列生成直方图。

无法为单列唯一索引所涵盖的列生成直方图。

直方图管理语句尝试尽可能多地执行所请求的操作,并报告剩余部分的诊断消息。 例如,如果 UPDATE HISTOGRAM 语句指定多个列,但其中一些列不存在或具有不受支持的数据类型,则会为其他列生成直方图,并为无效列生成消息。

所述 histogram_generation_max_mem_size 系统变量控制的可用于直方图生成存储器的最大量。 可以在运行时设置全局和会话值。

更改全局 histogram_generation_max_mem_size 值需要足以设置全局系统变量的权限。 更改会话 histogram_generation_max_mem_size 值需要足以设置受限会话系统变量的权限。 请参见 第5.1.9.1节“系统变量权限”

有关为直方图生成执行的内存分配的信息,请监视性能模式 memory/sql/histograms 工具。 请参见 第26.12.16.10节“内存汇总表”

直方图受这些DDL语句的影响:

  • DROP TABLE 删除已删除表中列的直方图。

  • DROP DATABASE 删除已删除数据库中任何表的直方图,因为该语句删除了数据库中的所有表。

  • RENAME TABLE 不删除直方图。 相反,它重命名重命名表的直方图以与新表名相关联。

  • ALTER TABLE 删除或修改列的语句删除该列的直方图。

  • ALTER TABLE ... CONVERT TO CHARACTER SET 删除字符列的直方图,因为它们受字符集更改的影响。 非字符列的直方图不受影响。

其他考虑因素

ANALYZE TABLE INFORMATION_SCHEMA.INNODB_TABLESTATS 表中 清除表统计信息 并将 STATS_INITIALIZED 设置 Uninitialized 下次访问表时将再次收集统计信息。

13.7.3.2检查表语法

检查表tbl_name[,tbl_name] ...... [ option] ......

option:{
    升级
  | 
  | 快速
  | 介质
  | EXTENDED
  | CHANGED
}

CHECK TABLE 检查一个或多个表是否有错误。 CHECK TABLE 还可以检查视图是否存在问题,例如视图定义中不再存在的表。

要检查表,您必须拥有一些权限。

CHECK TABLE 适用于 InnoDB MyISAM ARCHIVE ,和 CSV 表格。

在运行之前 CHECK TABLE InnoDB 表,请参见 检查表使用说明InnoDB表

CHECK TABLE 分区表支持,您可以 ALTER TABLE ... CHECK PARTITION 用来检查一个或多个分区; 有关更多信息,请参见 第13.1.9节“ALTER TABLE语法” 第23.3.4节“分区维护”

CHECK TABLE 忽略未编制索引的虚拟生成列。

检查表输出

CHECK TABLE 返回结果集,其中包含下表中显示的列。

Table 表名
Op 总是 check
Msg_type status error info note ,或 warning
Msg_text 信息性消息

该语句可能会为每个已检查的表生成许多行信息。 最后一行具有 Msg_type 的价值 status Msg_text 正常应该是 OK Table is already up to date 表示表的存储引擎表示不需要检查表。

检查版本兼容性

FOR UPGRADE 选项检查命名表是否与当前版本的MySQL兼容。 使用时 FOR UPGRADE ,服务器会检查每个表,以确定自表创建以来是否存在任何表的数据类型或索引中的任何不兼容的更改。 如果没有,检查成功。 否则,如果存在可能的不兼容性,则服务器会对表执行全面检查(可能需要一些时间)。

由于数据类型的存储格式已更改或排序顺序已更改,因此可能会出现不兼容问题。 我们的目标是避免这些变化,但偶尔也需要纠正比版本之间不兼容更糟糕的问题。

FOR UPGRADE 发现这些不兼容性:

检查数据一致性

下表显示了可以给出的其他检查选项。 这些选项将传递给存储引擎,存储引擎可能会使用或忽略它们。

类型 含义
QUICK 不要扫描行以检查错误的链接。 适用于 InnoDB MyISAM 表和视图。
FAST 仅检查未正确关闭的表。 被忽略了 InnoDB ; 仅适用于 MyISAM 表和视图。
CHANGED 仅检查自上次检查后已更改的表或未正确关闭的表。 被忽略了 InnoDB ; 仅适用于 MyISAM 表和视图。
MEDIUM 扫描行以验证已删除的链接是否有效。 这还计算行的密钥校验和,并使用计算的密钥校验和进行验证。 被忽略了 InnoDB ; 仅适用于 MyISAM 表和视图。
EXTENDED 对每行的所有键执行完整键查找。 这可确保表格100%一致,但需要很长时间。 被忽略了 InnoDB ; 仅适用于 MyISAM 表和视图。

您可以组合检查选项,如以下示例中快速检查表以确定它是否已正确关闭:

检查表test_table快速快速;
注意

如果 CHECK TABLE 发现与被标记为表上没有问题, 损坏 不正确关闭 CHECK TABLE 可以删除标记。

如果表已损坏,则问题很可能出现在索引中而不是数据部分中。 所有上述检查类型都会彻底检查索引,因此应该找到大多数错误。

要检查您认为合适的表,请不要使用选项或 QUICK 选项。 当你赶时间时应该使用后者,并且可以承担 QUICK 在数据文件中没有发现错误 的非常小的风险 (在大多数情况下,在正常使用情况下,MySQL应该在数据文件中发现任何错误。如果发生这种情况,表将被标记为 已损坏 ”, 并且在修复之前无法使用。)

FAST 并且 CHANGED 主要用于从脚本(例如,从 cron 执行 )中定期检查表。 在大多数情况下, FAST 是优先考虑的 CHANGED (唯一不喜欢的情况是,当您怀疑自己在 MyISAM 代码中 发现了错误时 。)

EXTENDED 只有在运行正常检查后才能使用,但在MySQL尝试更新行或按键查找行时仍会从表中获取错误。 如果正常检查成功,这是不太可能的。

使用 CHECK TABLE ... EXTENDED 可能会影响查询优化器生成的执行计划。

报告的一些问题 CHECK TABLE 无法自动纠正:

  • Found row where the auto_increment column has the value 0

    这意味着在表中有一行,其中 AUTO_INCREMENT 索引列包含值0.( AUTO_INCREMENT 通过使用 UPDATE 语句 将列显式设置为0, 可以创建一个列为 0 的行 。)

    这本身不是错误,但如果您决定转储表并将其还原或 ALTER TABLE 在表上 执行操作,则可能会导致问题 在这种情况下, AUTO_INCREMENT 列会根据 AUTO_INCREMENT 的规则更改值 ,这可能会导致诸如重复键错误之类的问题。

    要删除警告,请执行 UPDATE 语句以将列设置为0以外的某个值。

检查表InnoDB表的使用说明

以下说明适用于 InnoDB 表格:

  • 如果 CHECK TABLE 遇到损坏的页面,服务器将退出以防止错误传播(Bug#10132)。 如果在辅助索引中发生损坏但表数据是可读的,则运行 CHECK TABLE 仍可导致服务器退出。

  • 如果 CHECK TABLE 遇到 聚簇索引中 的损坏 DB_TRX_ID DB_ROLL_PTR 字段,则 CHECK TABLE 可能导致 InnoDB 访问无效的撤消日志记录,从而导致与 MVCC 相关的服务器退出。

  • 如果 CHECK TABLE 遇到 InnoDB 表或索引中的错误,它会报告错误,并且通常会标记索引,有时会将表标记为已损坏,从而阻止进一步使用索引或表。 此类错误包括辅助索引中的条目数不正确或链接不正确。

  • 如果 CHECK TABLE 在辅助索引中找到错误的条目数,则会报告错误但不会导致服务器退出或阻止访问该文件。

  • CHECK TABLE 调查索引页面结构,然后调查每个键入项。 它不验证指向聚簇记录的键指针或遵循 BLOB 指针 路径

  • InnoDB 表被存储在它自己的 .ibd 文件 ,第一个3 所述的 .ibd 文件包含标题信息,而不是表或索引数据。 CHECK TABLE 语句不会检测仅影响标题数据的不一致性。 要验证 InnoDB .ibd 文件 的全部内容 ,请使用 innochecksum 命令。

  • CHECK TABLE 在大型 InnoDB 运行 ,其他线程可能在 CHECK TABLE 执行 期间被阻止 为避免超时,信号量等待阈值(600秒)延长了2小时(7200秒)以进行 CHECK TABLE 操作。 如果 InnoDB 检测到信号量​​等待240秒或更长时间,则会开始将 InnoDB 监视器输出 打印 到错误日志。 如果锁定请求超出信号量等待阈值,则 InnoDB 中止该过程。 为了避免信号量等待超时的可能性,请运行 CHECK TABLE QUICK 而不是 CHECK TABLE

  • CHECK TABLE InnoDB SPATIAL 索引的 功能 包括R树有效性检查和检查以确保R树行计数与聚簇索引匹配。

  • CHECK TABLE 支持虚拟生成列上的二级索引,这些列受支持 InnoDB

  • 从MySQL 8.0.14开始, InnoDB 支持并行聚簇索引读取,这可以提高 CHECK TABLE 性能。 InnoDB CHECK TABLE 操作 期间两次读取聚簇索引 第二次读取可以并行执行。 innodb_parallel_read_threads 会话变量必须被设置为一个大于1的值用于并行聚簇索引读取发生。 默认值为4.用于执行并行聚簇索引读取的实际线程 innodb_parallel_read_threads 数由要扫描的索引子树 设置或数量决定,取较小者。

检查表MyISAM表的使用说明

以下说明适用于 MyISAM 表格:

  • CHECK TABLE 更新 MyISAM 表的 关键统计信息

  • 如果 CHECK TABLE 输出没有返回 OK 或者 Table is already up to date ,您通常应该对表进行修复。 请参见 第7.6节“MyISAM表维护和崩溃恢复”

  • 如果没有 指定 任何 CHECK TABLE 选项 QUICK MEDIUM 或者 EXTENDED 指定了动态格式 MyISAM 的默认检查类型 MEDIUM 这与 在表上 运行 myisamchk --medium-check的 tbl_name 结果相同 除非 指定 ,否则 默认检查类型也适用 MEDIUM 于静态格式 MyISAM 在这种情况下,默认值为 跳过行扫描 因为行很少被破坏。 CHANGED FAST QUICK CHANGED FAST

13.7.3.3 CHECKSUM TABLE语法

CHECKSUM TABLE tbl_name[,tbl_name] ... [QUICK | EXTENDED]

CHECKSUM TABLE 报告 表的内容的 校验和 您可以使用此语句验证备份,回滚或其他旨在将数据恢复到已知状态的操作之前和之后的内容相同。

此语句需要 SELECT 权限。

视图不支持此语句。 如果 CHECKSUM TABLE 针对视图 运行 ,则 Checksum 值始终为 NULL ,并返回警告。

对于不存在的表, CHECKSUM TABLE 返回 NULL 并生成警告。

在校验和操作期间,表被锁定,读取锁定为 InnoDB MyISAM

性能注意事项

默认情况下,逐行读取整个表并计算校验和。 对于大型表,这可能需要很长时间,因此您只会偶尔执行此操作。 这种逐行计算是您使用 EXTENDED 子句 InnoDB 以及除了之外的所有其他存储引擎 MyISAM 以及 MyISAM 不使用该 CHECKSUM=1 子句 创建的表所获得的

对于 MyISAM 使用该 CHECKSUM=1 子句 创建的表 CHECKSUM TABLE CHECKSUM TABLE ... QUICK 返回 可以非常快速地 返回的 实时 表校验和。 如果表不满足所有这些条件,则 QUICK 返回 方法 NULL QUICK 不支持 方法 InnoDB 有关 子句 的语法, 请参见 第13.1.20节“CREATE TABLE语法” CHECKSUM

校验和值取决于表行格式。 如果行格式更改,则校验和也会更改。 例如,对于时间类型,如存储格式 TIME DATETIME 以及 TIMESTAMP 在MySQL 5.6之前的MySQL 5.6.5改变,因此,如果5.5表升级到MySQL 5.6,校验和的值可能会改变。

重要

如果两个表的校验和不同,那么几乎可以肯定这些表在某种程度上是不同的。 但是,由于使用的散列函数 CHECKSUM TABLE 不能保证无冲突,因此两个不相同的表可能会产生相同的校验和。

13.7.3.4 OPTIMIZE TABLE语法

OPTIMIZE [NO_WRITE_TO_BINLOG | 本地]tbl_name[,tbl_name] ......

OPTIMIZE TABLE 重新组织表数据和关联索引数据的物理存储,以减少存储空间并提高访问表时的I / O效率。 对每个表所做的确切更改取决于 该表使用 存储引擎

OPTIMIZE TABLE 在这些情况下 使用 ,具体取决于表的类型:

  • 在对 InnoDB 具有自己的 .ibd文件 执行实质性插入,更新或删除操作之后, 因为它是在 innodb_file_per_table 启用选项的 情况下创建的 重新组织表和索引,并且可以回收磁盘空间以供操作系统使用。

  • FULLTEXT 对作为 InnoDB 表中 索引 一部分的列进行实质性插入,更新或删除操作之后 首先设置配置选项 innodb_optimize_fulltext_only=1 要将索引维护期保持在合理的时间,请设置 innodb_ft_num_word_optimize 选项以指定要在搜索索引中更新的单词数,并运行一系列 OPTIMIZE TABLE 语句,直到搜索索引完全更新为止。

  • 删除的大部分后 MyISAM ARCHIVE 表,或者使许多变化为 MyISAM ARCHIVE 具有可变长度的行表(表具有 VARCHAR VARBINARY BLOB ,或 TEXT 列)。 删除的行在链表中维护,后续 INSERT 操作重用旧的行位置。 您可以 OPTIMIZE TABLE 用来回收未使用的空间并对数据文件进行碎片整理。 在对表进行大量更改后,此语句还可能会提高使用该表的语句的性能,有时甚至会显着提高。

此语句需要 表的权限 SELECT INSERT 特权。

OPTIMIZE TABLE 工程 InnoDB MyISAM ARCHIVE 表。 OPTIMIZE TABLE 内存 NDB 表的 动态列也支持 它不适用于内存表的固定宽度列,也不适用于磁盘数据表。 OPTIMIZE 可以使用调整NDB Cluster表 的性能,该 --ndb-optimization-delay 控制在处理批次行之间等待的时间长度 OPTIMIZE TABLE 有关更多信息,请参阅 NDB Cluster 7.3中已解决的先前NDB群集问题

对于NDB Cluster表, OPTIMIZE TABLE 可以通过(例如)中断执行 OPTIMIZE 操作 的SQL线程来中断

默认情况下, OPTIMIZE TABLE 不能 使用任何其它存储引擎创建的表工作,并返回指示这种缺乏支持的结果。 您可以 OPTIMIZE TABLE 通过 使用该 选项 启动 mysqld 来为其他存储引擎工作 --skip-new 在这种情况下, OPTIMIZE TABLE 只是映射到 ALTER TABLE

此语句不适用于视图。

OPTIMIZE TABLE 分区表支持。 有关将此语句与分区表和表分区一起使用的信息,请参见 第23.3.4节“分区维护”

默认情况下,服务器将 OPTIMIZE TABLE 语句 写入 二进制日志,以便它们复制到复制从属服务器。 要禁止记录,请指定可选 NO_WRITE_TO_BINLOG 关键字或其别名 LOCAL

OPTIMIZE TABLE输出

OPTIMIZE TABLE 返回结果集,其中包含下表中显示的列。

Table 表名
Op 总是 optimize
Msg_type status error info note ,或 warning
Msg_text 信息性消息

OPTIMIZE TABLE table捕获并抛出将表统计信息从旧文件复制到新创建的文件时发生的任何错误。 例如。 如果所有者的用户ID .MYD .MYI 文件是从的用户ID不同 的mysqld 过程, OPTIMIZE TABLE 除非生成一个“不能改变文件的所有权”错误 的mysqld 由启动 root 用户。

InnoDB详细信息

对于 InnoDB 表, OPTIMIZE TABLE 映射到 ALTER TABLE ... FORCE ,重建表以更新索引统计信息并释放聚簇索引中未使用的空间。 OPTIMIZE TABLE 当您在 InnoDB 表格 上运行它时,它 会显示在输出中 ,如下所示:

mysql> OPTIMIZE TABLE foo;
+ ---------- + ---------- + ---------- + ---------------- -------------------------------------------------- -  +
| 表| Op | Msg_type | Msg_text |
+ ---------- + ---------- + ---------- + ---------------- -------------------------------------------------- -  +
| test.foo | 优化| 注意| 表不支持优化,而是重新创建+分析
| test.foo | 优化| 状态| 好的
+ ---------- + ---------- + ---------- + ---------------- -------------------------------------------------- -  +

OPTIMIZE TABLE 在线DDL 用于常规 InnoDB 和分区 表,从而减少并发DML操作的停机时间。 OPTIMIZE TABLE 封面 引发 并在封面下执行 的表重建 ALTER TABLE ... FORCE 已就位完成。 仅在操作的准备阶段和提交阶段期间短暂地进行独占表锁定。 在准备阶段,更新元数据并创建中间表。 在提交阶段,将提交表元数据更改。

OPTIMIZE TABLE 在以下条件下使用表复制方法重建表:

OPTIMIZE TABLE 包含 索引的 不支持 使用 联机DDL 而是使用表格复制方法。 InnoDB FULLTEXT

InnoDB 使用页面分配方法存储数据,并且不会像传统存储引擎(例如 MyISAM 那样遭受碎片 在考虑是否运行优化时,请考虑服务器将处理的事务的工作负载:

MyISAM详情

对于 MyISAM 表格, OPTIMIZE TABLE 工作如下:

  1. 如果表已删除或拆分行,请修复该表。

  2. 如果索引页未排序,请对它们进行排序。

  3. 如果表的统计信息不是最新的(并且无法通过对索引进行排序来完成修复),请更新它们。

其他考虑因素

OPTIMIZE TABLE 在线执行常规和分区 InnoDB 表。 否则,MySQL 会在 OPTIMIZE TABLE 运行 期间 锁定表

OPTIMIZE TABLE 不对R树索引进行排序,例如 POINT 上的空间索引 (缺陷号23578)

13.7.3.5 REPAIR TABLE语法

维修[NO_WRITE_TO_BINLOG | 本地]tbl_name[,tbl_name] ......
    [QUICK] [EXTENDED] [USE_FRM]

REPAIR TABLE 修复可能已损坏的表,仅适用于某些存储引擎。

此语句需要 表的权限 SELECT INSERT 特权。

虽然通常你不应该运行 REPAIR TABLE ,但是如果发生灾难,这个语句很可能会从 MyISAM 表中 获取所有数据 如果您的表经常损坏,请尝试找到它的原因,以消除使用的需要 REPAIR TABLE 请参见 第B.4.3.3节“如果MySQL不断崩溃该怎么办” ,以及 第16.2.4节“MyISAM表问题”

REPAIR TABLE 检查表以查看是否需要升级。 如果是,则按照与之相同的规则执行升级 CHECK TABLE ... FOR UPGRADE 有关 更多信息 请参见 第13.7.3.2节“CHECK TABLE语法”

重要
  • 在执行表修复操作之前备份表; 在某些情况下,操作可能会导致数据丢失。 可能的原因包括但不限于文件系统错误。 请参见 第7章, 备份和恢复

  • 如果服务器在 REPAIR TABLE 操作 期间崩溃 ,则在重新启动它之后必须立即执行 REPAIR TABLE 该表的 另一个 语句,然后再对其执行任何其他操作。 在最坏的情况下,您可能有一个新的干净索引文件,但没有关于数据文件的信息,然后您执行的下一个操作可能会覆盖该数据文件。 这是一种不太可能但可能的情况,强调了首先进行备份的价值。

  • 如果主服务器上的表已损坏并且您 REPAIR TABLE 在其上 运行 ,则对原始表的任何更改都 不会 传播到从服务器。

REPAIR TABLE存储引擎和分区支持

REPAIR TABLE 工程 MyISAM ARCHIVE CSV 表。 对于 MyISAM 表格, 默认情况下 它与 myisamchk --recover tbl_name 具有相同的效果 此语句不适用于视图。

REPAIR TABLE 分区表支持。 但是,该 USE_FRM 选项不能与分区表上的此语句一起使用。

您可以 ALTER TABLE ... REPAIR PARTITION 用来修复一个或多个分区; 有关更多信息,请参见 第13.1.9节“ALTER TABLE语法” 第23.3.4节“分区维护”

修复表选项
  • NO_WRITE_TO_BINLOG 要么 LOCAL

    默认情况下,服务器将 REPAIR TABLE 语句 写入 二进制日志,以便它们复制到复制从属服务器。 要禁止记录,请指定可选 NO_WRITE_TO_BINLOG 关键字或其别名 LOCAL

  • QUICK

    如果使用该 QUICK 选项,则 REPAIR TABLE 尝试仅修复索引文件,而不是数据文件。 这种类型的修复就像 myisamchk --recover --quick 所做的那样

  • EXTENDED

    如果使用该 EXTENDED 选项,MySQL会逐行创建索引,而不是一次创建一个索引并进行排序。 这种类型的修复就像 myisamchk --safe-recover 所做的 那样

  • USE_FRM

    USE_FRM 如果 .MYI 索引文件丢失或其标头已损坏, 则可以使用 选项 此选项告诉MySQL不要信任 .MYI 文件头中 的信息, 并使用数据字典中的信息重新创建它。 使用 myisamchk 无法进行此类修复

    警告

    在无法使用常规 模式 时才 使用该 USE_FRM 选项 告诉服务器忽略该 文件会使重要的表元数据存储在 修复过程不可用的状态,这可能会产生有害后果: REPAIR .MYI .MYI

    • 当前 AUTO_INCREMENT 值丢失。

    • 表中已删除记录的链接将丢失,这意味着已删除记录的可用空间此后将保持未被占用状态。

    • .MYI 报头指示该表是否被压缩。 如果服务器忽略此信息,则无法判断表是否已压缩,并且修复可能导致表内容的更改或丢失。 这意味着 USE_FRM 不应该与压缩表一起使用。 无论如何,这应该是不必要的:压缩表是只读的,因此它们不应该被破坏。

    如果您使用 USE_FRM 的是由不同版本的MySQL服务器创建的表而不是当前正在运行 REPAIR TABLE 的表 则不会尝试修复该表。 在这种情况下,返回的结果集 REPAIR TABLE 包含 Msg_type 值为 error Msg_text 值为的行 Failed repairing incompatible .FRM file

    如果 USE_FRM 使用, REPAIR TABLE 则不检查表以查看是否需要升级。

修复表输出

REPAIR TABLE 返回结果集,其中包含下表中显示的列。

Table 表名
Op 总是 repair
Msg_type status error info note ,或 warning
Msg_text 信息性消息

REPAIR TABLE 语句可能会为每个已修复的表生成许多行信息。 最后一行具有 Msg_type 的价值 status Msg_test 正常应该是 OK 对于一张 MyISAM 桌子,如果你没有 OK ,你应该尝试用 myisamchk 修复它 --safe-recover REPAIR TABLE 没有实现 myisamchk的 所有选项 。使用 myisamchk --safe-recover ,您也可以使用 REPAIR TABLE 不支持的 选项 ,例如 --max-record-length 。)

REPAIR TABLE table捕获并抛出将表统计信息从旧的损坏文件复制到新创建的文件时发生的任何错误。 例如。 如果所有者的用户ID .MYD .MYI 文件是从的用户ID不同 的mysqld 过程, REPAIR TABLE 除非生成一个“不能改变文件的所有权”错误 的mysqld 由启动 root 用户。

表修复注意事项

REPAIR TABLE 如果表包含5.6.4之前格式的旧时间列( TIME DATETIME TIMESTAMP 不支持小数秒精度的列 ,并且 avoid_temporal_upgrade 系统变量被禁用 ),则对 表进行升级 如果 avoid_temporal_upgrade 已启用,则 REPAIR TABLE 忽略表中存在的旧时间列,并且不升级它们。

要升级包含此类时间列的表,请 avoid_temporal_upgrade 在执行前 禁用 REPAIR TABLE

您可以 REPAIR TABLE 通过设置某些系统变量 来提高 性能。 请参见 第8.6.3节“优化REPAIR TABLE语句”

13.7.4组件,插件和用户定义的功能语句

13.7.4.1 CREATE FUNCTION用户定义函数的语法

创建[AGGREGATE]功能 function_name
    退货{STRING | INTEGER | REAL | DECIMAL}
    SONAME shared_library_name

用户定义函数(UDF)是一种使用新函数扩展MySQL的方法,该函数类似于本机(内置)MySQL函数,如 ABS() CONCAT()

function_name 是应该在SQL语句中用于调用函数的名称。 RETURNS 子句指示函数返回值的类型。 DECIMAL 是一个合法的值 RETURNS ,但目前 DECIMAL 函数返回字符串值,应该像 STRING 函数 一样编写

shared_library_name 是包含实现该功能的代码的共享库文件的基本名称。 该文件必须位于插件目录中。 该目录由 plugin_dir 系统变量 的值给出 有关更多信息,请参见 第5.7.1节“安装和卸载用户定义的函数”

要创建函数,您必须具有 系统数据库 INSERT 权限 mysql 这是必要的,因为 CREATE FUNCTION mysql.func 系统表 添加一行 ,记录函数的名称,类型和共享库名称。

使用注册的UDF CREATE FUNCTION 列在Performance Schema user_defined_functions 表中; 请参见 第26.12.17.6节“user_defined_functions表”

活动功能是已加载但 CREATE FUNCTION 未被删除的功能 DROP FUNCTION 每次服务器启动时都会重新加载所有活动函数,除非您 使用该 选项 启动 mysqld --skip-grant-tables 在这种情况下,将跳过UDF初始化并且UDF不可用。

有关编写用户定义函数的说明,请参见 第29.4.2节“添加新的用户定义函数” 要使UDF机制起作用,函数必须用C或C ++(或其他可以使用C调用约定的语言)编写,操作系统必须支持动态加载,并且必须 动态 编译 mysqld (非静态 编译 )。

一个 AGGREGATE 函数的工作原理完全像一个本地的MySQL骨料(摘要)功能,如 SUM COUNT()

注意

要升级与UDF关联的共享库,请发出 DROP FUNCTION 语句,升级共享库,然后发出 CREATE FUNCTION 语句。 如果先升级共享库然后再使用 DROP FUNCTION ,则服务器可能会崩溃。

13.7.4.2 DROP FUNCTION语法

降功能 function_name

此语句删除名为的用户定义函数(UDF) function_name

要删除函数,您必须具有 系统数据库 DELETE 权限 mysql 这是因为 DROP FUNCTION mysql.func 系统表中 删除了一行,该行 记录了函数的名称,类型和共享库名称。

注意

要升级与UDF关联的共享库,请发出 DROP FUNCTION 语句,升级共享库,然后发出 CREATE FUNCTION 语句。 如果先升级共享库然后再使用 DROP FUNCTION ,则服务器可能会崩溃。

DROP FUNCTION 也用于删除存储的函数(参见 第13.1.29节“DROP PROCEDURE和DROP FUNCTION语法” )。

13.7.4.3安装组件语法

安装组件component_name[,component_name] ...

此语句将安装一个或多个服务器组件,这些组件将立即生效。 组件提供服务器和其他组件可用的服务; 请参见 第5.5节“MySQL服务器组件” INSTALL COMPONENT 需要 系统表 INSERT 权限 mysql.component

例:

INSTALL COMPONENT'file:// component1','file:// component2';

组件名称是以开头的URN, file:// 并指示实现组件的文件的基本名称,位于 plugin_dir 系统变量 指定的目录中 组件名称不包括任何与平台相关的文件名后缀,例如 .so .dll (这些命名细节可能会发生变化,因为组件名称解释本身是由服务执行的,组件基础结构使得可以用替代实现替换默认服务实现。)

如果发生任何错误,语句将失败并且无效。 例如,如果组件名称错误,命名组件不存在或已安装,或组件初始化失败,则会发生这种情况。

加载器服务处理组件加载,包括将已安装的组件添加到 mysql.component 充当注册表 系统表中。 对于后续服务器重新启动, mysql.component 加载器服务在启动序列期间加载 列出的任何组件 即使使用该 --skip-grant-tables 选项 启动服务器,也会发生这种情况

如果组件依赖于注册表中不存在的服务,并且您尝试安装组件而不安装提供其所依赖的服务的组件,则会发生错误:

ERROR 3527(HY000):无法满足服务'component_a'的依赖性
组件'component_b'需要。

要避免此问题,请在同一语句中安装所有组件,或者在安装依赖组件所依赖的任何组件之后安装它们。

13.7.4.4安装PLUGIN语法

安装插件plugin_nameSONAME' shared_library_name'

此语句安装服务器插件。 它需要 系统表 INSERT 权限 mysql.plugin

plugin_name 是库文件中包含的插件描述符结构中定义的插件的名称(请参见 第29.2.4.2节“插件数据结构” )。 插件名称不区分大小写。 为了获得最大兼容性,插件名称应限制为ASCII字母,数字和下划线,因为它们用于C源文件,shell命令行,M4和Bourne shell脚本以及SQL环境。

shared_library_name 是包含插件代码的共享库的名称。 该名称包括文件扩展名(例如, libmyplugin.so libmyplugin.dll ,或 libmyplugin.dylib )。

共享库必须位于插件目录( plugin_dir 系统变量 指定的目录 )中。 该库必须位于插件目录本身,而不是在子目录中。 默认情况下, plugin_dir 配置变量 plugin 指定 目录下的目录 pkglibdir ,但可以通过设置 plugin_dir 服务器启动时 的值来更改 目录 例如,将其值设置在 my.cnf 文件中:

的[mysqld]
PLUGIN_DIR =/path/to/plugin/directory

如果值 plugin_dir 是相对路径名,则将其视为相对于MySQL基目录( basedir 系统变量 的值 )。

INSTALL PLUGIN 加载并初始化插件代码以使插件可供使用。 插件通过执行其初始化函数进行初始化,该函数处理插件在使用之前必须执行的任何设置。 当服务器关闭时,它会为每个加载的插件执行取消初始化函数,以便插件有机会执行任何最终的清理。

INSTALL PLUGIN 还通过向 mysql.plugin 系统表 添加指示插件名称和库文件名的行来注册插件 在服务器启动时,服务器会加载并初始化其中列出的任何插件 mysql.plugin 这意味着插件只安装 INSTALL PLUGIN 一次,而不是每次服务器启动时安装。 如果使用该 --skip-grant-tables 选项 启动服务器,则不会在启动时加载插件

插件库可以包含多个插件。 对于每个要安装的,请使用单独的 INSTALL PLUGIN 语句。 每个语句都命名一个不同的插件,但它们都指定了相同的库名。

INSTALL PLUGIN 使服务器 my.cnf 像在服务器启动期间一样 读取option( )文件。 这使插件能够从这些文件中获取任何相关选项。 即使在加载插件之前(如果使用 loose 前缀) ,也可以将插件选项添加到选项文件中 也可以再次卸载插件,编辑 my.cnf 和安装插件。 以这种方式重新启动插件使其能够在不重新启动服务器的情况下使用新选项值。

有关在服务器启动时控制单个插件加载的选项,请参见 第5.6.1节“安装和卸载插件” 如果在 --skip-grant-tables 给出选项 时需要为单个服务器启动加载插件 (这告诉服务器不要读取系统表),请使用该 --plugin-load 选项。 请参见 第5.1.7节“服务器命令选项”

要删除插件,请使用该 UNINSTALL PLUGIN 语句。

有关插件加载的其他信息,请参见 第5.6.1节“安装和卸载插件”

要查看安装了哪些插件,请使用该 SHOW PLUGINS 语句或查询 INFORMATION_SCHEMA PLUGINS 表。

如果重新编译插件库并需要重新安装它,则可以使用以下任一方法:

  • 使用 UNINSTALL PLUGIN 卸载所有插件库,安装在插件目录中的新插件的库文件,然后使用 INSTALL PLUGIN 安装的所有插件库。 此过程的优点是可以在不停止服务器的情况下使用它。 但是,如果插件库包含许多插件,则必须发出许多 INSTALL PLUGIN UNINSTALL PLUGIN 语句。

  • 停止服务器,在插件目录中安装新的插件库文件,然后重新启动服务器。

13.7.4.5 UNINSTALL COMPONENT语法

卸载组件component_name[,component_name] ......

此语句停用并卸载一个或多个服务器组件。 组件提供服务器和其他组件可用的服务; 请参见 第5.5节“MySQL服务器组件” UNINSTALL COMPONENT 是补充 INSTALL COMPONENT 它需要 系统表 DELETE 权限 mysql.component

例:

UNINSTALL COMPONENT'file:// component1','file:// component2';

有关组件命名的信息,请参见 第13.7.4.3节“安装组件语法”

如果发生任何错误,语句将失败并且无效。 例如,如果组件名称错误,未安装命名组件或无法卸载,则会发生这种情况,因为其他已安装的组件依赖于它。

加载器服务处理组件卸载,其中包括从 mysql.component 充当注册表 系统表中 删除已卸载的组件 因此,在启动过程中不会加载卸载的组件,以便后续服务器重新启动。

13.7.4.6 UNINSTALL PLUGIN语法

卸载插件 plugin_name

此语句删除已安装的服务器插件。 它需要 系统表 DELETE 权限 mysql.plugin UNINSTALL PLUGIN 是补充 INSTALL PLUGIN

plugin_name 必须是 mysql.plugin 表中 列出的某个插件的名称 服务器执行插件的取消 mysql.plugin 初始化 函数并从 系统表中 删除插件的行 ,以便后续服务器重新启动不会加载并初始化插件。 UNINSTALL PLUGIN 不会删除插件的共享库文件。

如果任何使用它的表打开,则无法卸载插件。

删除插件会影响关联表的使用。 例如,如果全文解析器插件与 FULLTEXT 表上的索引 相关联 ,则卸载插件会使表无法使用。 任何访问该表的尝试都会导致错误。 该表甚至无法打开,因此您无法删除使用该插件的索引。 这意味着除非您不关心表内容,否则卸载插件是需要小心的。 如果你正在卸载插件而不想在以后重新安装它而你关心表内容,你应该使用 mysqldump 转储表 WITH PARSER 从dumped中 删除该 子句 CREATE TABLE 语句,以便您以后可以重新加载表。 如果您不关心该表, DROP TABLE 即使缺少与该表关联的任何插件 也可以使用该表。

有关插件加载的其他信息,请参见 第5.6.1节“安装和卸载插件”

13.7.5 SET语法

SET 声明有几种形式。 与特定服务器功能无关的表单的描述显示在本节的小节中:

其他表单的描述出现在别处,与其帮助实现的功能相关的其他语句组合在一起:

13.7.5.1变量赋值的SET语法

SET variable= expr[,variable= expr] ......

variable:{
     user_var_name
  | param_name
  | local_var_name
  | {GLOBAL | @@ GLOBAL。} system_var_name
  | {PERSIST | @@ PERSIST。} system_var_name
  | {PERSIST_ONLY | @@ PERSIST_ONLY。} system_var_name
  | [会话| @@会议。| @@]system_var_name
}

SET 变量赋值的语法使您可以将值分配给影响服务器或客户端操作的不同类型的变量:

一个 SET 是分配变量值的语句不写入二进制日志,因此在复制方案只会影响您在其上执行它的主机。 要影响所有复制主机,请在每个主机上执行该语句。

以下部分描述 SET 了设置变量的语法。 它们使用 = 赋值运算符,但 := 也允许赋值运算符用于此目的。

用户定义的变量赋值

用户定义的变量在会话中本地创建,仅存在于该会话的上下文中; 请参见 第9.4节“用户定义的变量”

用户定义的变量写为 并赋予表达式值,如下所示: @var_name

SET @ var_name= expr;

例子:

SET @name = 43;
SET @total_tax =(SELECT SUM(tax)FROM taxable_transactions);

正如这些语句所证明的那样, expr 范围从简单(文字值)到更复杂(标量子查询返回的值)。

Performance Schema user_variables_by_thread 表包含有关用户定义变量的信息。 请参见 第26.12.10节“性能模式用户定义变量表”

参数和局部变量赋值

SET 适用于定义它们的存储对象上下文中的参数和局部变量。 以下过程使用 increment procedure参数和 counter 局部变量:

CREATE PROCEDURE p(增量INT)
开始
  DECLARE计数器INT DEFAULT 0;
  WHILE counter <10 DO
    -  ... 做工作 ...
    SET counter = counter + increment;
  结束时间;
结束;
系统变量分配

MySQL服务器维护配置其操作的系统变量。 系统变量可以具有影响整个服务器操作的全局值,影响当前会话的会话值,或两者。 许多系统变量是动态的,可以在运行时使用该 SET 语句 更改, 以影响当前服务器实例的操作。 SET 也可用于将某些系统变量持久保存到 mysqld-auto.cnf 数据目录中 文件,以影响后续启动的服务器操作。

如果更改会话系统变量,则该值在会话中保持有效,直到您将变量更改为其他值或会话结束。 此更改对其他会话没有影响。

如果更改全局系统变量,则会记住该值并用于初始化新会话的会话值,直到将变量更改为其他值或服务器退出为止。 访问全局值的任何客户端都可以看到此更改。 但是,更改仅影响更改后连接的客户端的相应会话值。 全局变量更改不会影响任何当前客户端会话的会话值(甚至不会影响发生全局值更改的会话)。

要使全局系统变量设置为永久性以便在服务器重新启动时应用,可以将其持久保存到 mysqld-auto.cnf 数据目录中 文件中。 也可以通过手动修改 my.cnf 选项文件 来进行持久的配置更改 ,但这样做更麻烦,并且手动输入的设置中的错误可能要到很晚才能发现。 SET 持久化系统变量的语句更方便,并避免设置格式错误的可能性,因为具有语法错误的设置不会成功并且不会更改服务器配置。 有关保留系统变量和 mysqld-auto.cnf 文件的 详细信息 ,请参阅 第5.1.9.3节“持久系统变量”

注意

设置或保持全局系统变量值始终需要特殊权限。 设置会话系统变量值通常不需要特殊权限,可以由任何用户完成,但也有例外。 有关更多信息,请参见 第5.1.9.1节“系统变量权限”

以下讨论描述了设置和保存系统变量的语法选项:

  • 要为全局系统变量赋值,请在变量名前面加上 GLOBAL 关键字或 @@GLOBAL. 限定符:

    SET GLOBAL max_connections = 1000;
    SET @@ GLOBAL.max_connections = 1000;
    
  • 要分配一个值到会话系统变量,由前面的变量名 SESSION LOCAL 关键字,由 @@SESSION. @@LOCAL. @@ 预选赛,或没有关键字或者没有修饰可言:

    SET SESSION sql_mode ='TRADITIONAL';
    SET LOCAL sql_mode ='TRADITIONAL';
    SET @@ SESSION.sql_mode ='TRADITIONAL';
    SET @@ LOCAL.sql_mode ='TRADITIONAL';
    SET @@ sql_mode ='TRADITIONAL';
    SET sql_mode ='TRADITIONAL';
    

    客户端可以更改自己的会话变量,但不能更改任何其他客户端的变量。

  • 要将全局系统变量持久保存到 mysqld-auto.cnf 数据目录中 选项文件,请在变量名前面加上 PERSIST 关键字或 @@PERSIST. 限定符:

    SET PERSIST max_connections = 1000;
    SET @@ PERSIST.max_connections = 1000;
    

    SET 语法使您可以在运行时进行配置更改,这些更改也会在服务器重新启动时保持不变。 比如 SET GLOBAL SET PERSIST 设置全局变量运行时值,但也将变量设置写入 mysqld-auto.cnf 文件(如果有的话,替换任何现有的变量设置)。

  • 要在 mysqld-auto.cnf 不设置全局变量运行时值的情况下将 全局系统变量保留到 文件,请在变量名前面加上 PERSIST_ONLY 关键字或 @@PERSIST_ONLY. 限定符:

    SET PERSIST_ONLY back_log = 100;
    SET @@ PERSIST_ONLY.back_log = 100;
    

    比如 PERSIST PERSIST_ONLY 将变量设置写入 mysqld-auto.cnf 但是,与之不同 PERSIST PERSIST_ONLY 不会修改全局变量运行时值。 PERSIST_ONLY 适用于配置只能在服务器启动时设置的只读系统变量。

要将已编译的MySQL缺省值或会话系统变量的全局系统变量值设置为当前对应的全局值,请将该变量设置为该值 DEFAULT 例如,以下两个语句在将会话值设置 max_join_size 为当前全局值时 完全相同

SET @@ SESSION.max_join_size = DEFAULT;
SET @@ SESSION.max_join_size = @@ GLOBAL.max_join_size;

使用 SET 一个全局系统变量坚持到的值 DEFAULT 或者它的字面默认值赋给变量的默认值,并增加了对变量的设置 mysqld-auto.cnf 要从文件中删除变量,请使用 RESET PERSIST

某些系统变量无法保留或持久受限。 请参见 第5.1.9.4节“不可容忍且持久限制的系统变量”

如果在 SET 执行语句 时安装了插件,则可以持久保存由插件实现的系统变量 如果仍然安装了插件,则持久插件变量的分配将对后续服务器重新启动生效。 如果不再安装插件,则在服务器读取 mysqld-auto.cnf 文件 时,插件变量将不存在 在这种情况下,服务器会向错误日志写入警告并继续:

目前未知的变量' var_name'
从持久化的配置文件中读取

要显示系统变量名称和值:

设置错误处理

如果语句中的任何变量赋值 SET 失败,则整个语句将失败,并且不会更改任何变量,也不会 mysqld-auto.cnf 更改文件。

SET 在这里描述的情况下产生错误。 大多数例子都显示出来 SET 使用关键字语法的语句(例如, GLOBAL SESSION ),但对于使用相应修饰符(例如, @@GLOBAL. @@SESSION. )的 语句,原则也是如此

  • 使用 SET (任何变体)设置只读变量:

    MySQL的> SET GLOBAL version = 'abc';
    ERROR 1238(HY000):变量'version'是只读变量
    
  • 用于 GLOBAL PERSIST PERSIST_ONLY 设定一个只有一个会话值的变量:

    MySQL的> SET GLOBAL sql_log_bin = ON;
    ERROR 1228(HY000):变量'sql_log_bin'是一个SESSION
    变量,不能与SET GLOBAL一起使用
    
  • 用于 SESSION 设置是只有一个全局值的变量:

    MySQL的> SET SESSION max_connections = 1000;
    ERROR 1229(HY000):变量'max_connections'是a
    GLOBAL变量,应使用SET GLOBAL设置
    
  • 遗漏的 GLOBAL PERSIST PERSIST_ONLY 设定一个只有一个全局值的变量:

    MySQL的> SET max_connections = 1000;
    ERROR 1229(HY000):变量'max_connections'是a
    GLOBAL变量,应使用SET GLOBAL设置
    
  • 使用 PERSIST PERSIST_ONLY 设置无法持久化的变量:

    MySQL的> SET PERSIST port = 3307;
    ERROR 1238(HY000):变量'port'是只读变量
    MySQL的> SET PERSIST_ONLY port = 3307;
    ERROR 1238(HY000):变量'port'是非持久只读变量
    
  • @@GLOBAL. @@PERSIST. @@PERSIST_ONLY. @@SESSION. ,和 @@ 修饰只适用于系统变量。 尝试将它们应用于用户定义的变量,存储过程或函数参数或存储的程序局部变量时发生错误。

  • 并非所有系统变量都可以设置为 DEFAULT 在这种情况下,将 DEFAULT 结果 分配给 错误。

  • 尝试分配 DEFAULT 给用户定义的变量,存储过程或函数参数或存储的程序局部变量时发生错误。

多变量分配

一个 SET 语句可以包含多个变量赋值,以逗号分隔。 此语句将值分配给用户定义的变量和系统变量:

SET @x = 1,SESSION sql_mode ='';

如果你在一个声明中设置多个系统变量,最近一段时间 GLOBAL PERSIST PERSIST_ONLY ,或 SESSION 在声明中关键字用于以下有没有指定的关键字分配。

多变量赋值的示例:

SET GLOBAL sort_buffer_size = 1000000,SESSION sort_buffer_size = 1000000;
SET @@ GLOBAL.sort_buffer_size = 1000000,@@ LOCAL.sort_buffer_size = 1000000;
SET GLOBAL max_connections = 1000,sort_buffer_size = 1000000;

@@GLOBAL. @@PERSIST. @@PERSIST_ONLY. @@SESSION. ,和 @@ 修饰只适用于紧随其后的系统变量,没有任何剩余的系统变量。 此语句将 sort_buffer_size 全局值设置为50000,将会话值设置为1000000:

SET @@ GLOBAL.sort_buffer_size = 50000,sort_buffer_size = 1000000;
表达式中的系统变量引用

要在表达式中引用系统变量的值,请使用其中一个 @@ -modifiers(除了 @@PERSIST. @@PERSIST_ONLY. ,表达式中不允许)。 例如,您可以在如下 SELECT 语句中 检索系统变量值

SELECT @@ GLOBAL.sql_mode,@@ SESSION.sql_mode,@@ sql_mode;
注意

对表达式中的系统变量的引用为 而不是 )将返回会话值(如果存在),否则返回全局值。 这不同于 ,它总是指会话值。 @@var_name @@ @@GLOBAL. @@SESSION. SET @@var_name = expr

13.7.5.2 SET CHARACTER SET语法

SET {CHARACTER SET | CHARSET}
    {' charset_name'| 默认}

此语句将使用给定映射映射服务器和当前客户端之间发送的所有字符串。 SET CHARACTER SET 设置三个会话系统变量: character_set_client character_set_results 设置为给定的字符集,并 character_set_connection 设置为值 character_set_database 请参见 第10.4节“连接字符集和排序”

charset_name 可以引用或不引用。

可以使用该值恢复默认字符集映射 DEFAULT 默认值取决于服务器配置。

某些字符集不能用作客户端字符集。 试图使用它们 SET CHARACTER SET 会产生错误。 请参见 不允许的客户端字符集

13.7.5.3 SET NAMES语法

设置名称{' charset_name'
    [COLLATE' collation_name'] | 默认}

该语句设置三届系统变量 character_set_client character_set_connection 以及 character_set_results 给定的字符集。 设置 character_set_connection charset_name 也设置 collation_connection 为默认排序规则 charset_name 请参见 第10.4节“连接字符集和排序”

可选 COLLATE 子句可用于明确指定排序规则。 如果给定,则排序规则必须是允许的排序规则之一 charset_name

charset_name 并且 collation_name 可以引用或不引用。

可以使用值来恢复默认映射 DEFAULT 默认值取决于服务器配置。

某些字符集不能用作客户端字符集。 试图使用它们 SET NAMES 会产生错误。 请参见 不允许的客户端字符集

13.7.6 SHOW语法

SHOW 有许多表单提供有关服务器的数据库,表,列或状态信息的信息。 本节介绍以下内容:

显示{BINARY | MASTER} LOGS
显示BINLOG事件[IN' log_name'] [FROM pos] [LIMIT [ offset,] row_count]
显示字符集[ like_or_where]
SHOW COLLATION [ like_or_where]tbl_name[FROM db_name] [ like_or_where] 显示[FULL] COLUMNS
显示创建数据库db_name
显示创建事件event_name
显示创建功能func_name
显示创建过程proc_name
显示创建表tbl_name
显示创建触发器trigger_name
显示创建视图view_name
显示数据库[ like_or_where]
SHOW ENGINE engine_name{STATUS | MUTEX}
显示[存储]发动机
显示错误[限制[ offset,] row_count]
展示活动
显示功能代码func_name
显示功能状态[ like_or_where]
显示[FROM ] user
显示索引的资助tbl_namedb_name
显示主要状态
显示打开的表格[FROM db_name] [ like_or_where]
显示插件
显示程序代码proc_name
显示程序状态[ like_or_where]
显示特权
显示[FULL] PROCESSLIST
SHOW PROFILE [ types] [FOR QUERY n] [OFFSET n] [LIMIT n]
显示配置文件
显示RELAYLOG活动[IN' log_name'] [FROM pos] [LIMIT [ offset,] row_count]
SHOW SLAVE HOSTS
SHOW SLAVE STATUS [FOR CHANNEL channel]
SHOW [GLOBAL | 会话]状态[ like_or_where]
SHOW TABLE STATUS [FROM db_name] [ like_or_where]
SHOW [FULL] TABLES [FROM db_name] [ like_or_where]
SHOW TRIGGERS [FROM db_name] [ like_or_where]
SHOW [GLOBAL | 会话] VARIABLES [ like_or_where]
显示警告[限制[ offset,] row_count]

like_or_where
    喜欢' pattern'
  | 哪里expr

如果给定 SHOW 语句 的语法 包含一个 部分, 则是一个可以包含SQL 通配符的字符串。 该模式对于将语句输出限制为匹配值很有用。 LIKE 'pattern' 'pattern' % _

有几个 SHOW 语句也接受一个 WHERE 子句,它在指定要显示的行方面提供了更大的灵活性。 请参见 第25.42节“扩展显示语句”

许多MySQL API(例如PHP)使您能够像处理 SHOW 结果集一样 处理从 语句 返回 的结果 SELECT ; 有关更多信息, 请参见 第28章, 连接器和API 或API文档。 此外,您可以在SQL中使用对 INFORMATION_SCHEMA 数据库中的 表的查询结果 ,而这些结果对于 SHOW 语句的 结果是不容易的 请参见 第25章, INFORMATION_SCHEMA表

13.7.6.1 SHOW BINARY LOGS语法

显示二进制日志
显示主日志

列出服务器上的二进制日志文件。 此语句用作 第13.4.1.1节“PURGE BINARY LOGS语法”中 描述的过程的一部分,该过程 说明了如何确定可以清除哪些日志。 SHOW BINARY LOGS 需要 REPLICATION CLIENT SUPER 特权。

加密的二进制日志文件具有512字节的文件头,其存储加密和解密文件所需的信息。 这包含在显示的文件大小中 SHOW BINARY LOGS Encrypted 列显示二进制日志文件是否已加密。 如果 binlog_encryption=ON 为服务器设置了 二进制日志加密,则它是活动 的。 如果在服务器运行时激活或停用二进制日志加密,则不会对现有二进制日志文件进行加密或解密。

MySQL的> SHOW BINARY LOGS;
+ --------------- + ----------- ----------- + +
| Log_name | File_size | 加密|
+ --------------- + ----------- ----------- + +
| binlog.000015 | 724935 | 是的|
| binlog.000016 | 733481 | 是的|
+ --------------- + ----------- ----------- + +

SHOW MASTER LOGS 相当于 SHOW BINARY LOGS

13.7.6.2显示BINLOG事件语法

展示BINLOG活动
   [IN' log_name']
   [FROM pos]
   [限制[ offset,] row_count]

显示二进制日志中的事件。 如果未指定 ,则显示第一个二进制日志。 需要 特权。 'log_name' SHOW BINLOG EVENTS REPLICATION SLAVE

LIMIT 子句的语法与 SELECT 语句 相同 请参见 第13.2.10节“SELECT语法”

注意

发出 SHOW BINLOG EVENTS with no LIMIT 子句可能会启动耗费时间和资源的过程,因为服务器会向客户端返回二进制日志的完整内容(包括修改数据的服务器执行的所有语句)。 作为替代方案 SHOW BINLOG EVENTS ,使用 mysqlbinlog 实用程序将二进制日志保存到文本文件中以供以后检查和分析。 请参见 第4.6.8节“ mysqlbinlog - 处理二进制日志文件的实用程序”

SHOW BINLOG EVENTS 显示二进制日志中每个事件的以下字段:

  • Log_name

    要列出的文件的名称。

  • Pos

    事件发生的位置。

  • Event_type

    描述事件类型的标识符。

  • Server_id

    发生事件的服务器的服务器ID。

  • End_log_pos

    下一个事件开始的位置,等于 Pos 加上事件的大小。

  • Info

    有关事件类型的更多详细信息。 此信息的格式取决于事件类型。

注意

与设置用户和系统变量有关的一些事件不包括在输出中 SHOW BINLOG EVENTS 要完全覆盖二进制日志中的事件,请使用 mysqlbinlog

注意

SHOW BINLOG EVENTS 没有 与中继日志文件。 你可以用它 SHOW RELAYLOG EVENTS 来达到这个目的。

13.7.6.3 SHOW CHARACTER SET语法

显示字符集
    [喜欢' pattern'| 在哪里expr]

SHOW CHARACTER SET 语句显示所有可用的字符集。 LIKE 子句(如果存在)指示要匹配的字符集名称。 WHERE 子句可以使用更一般的条件来选择行,如 第25.42节“扩展到SHOW语句”中所述 例如:

MySQL的> SHOW CHARACTER SET LIKE 'latin%';
+ --------- + ----------------------------- + --------- ---------- + -------- +
| Charset | 说明| 默认排序规则| Maxlen |
+ --------- + ----------------------------- + --------- ---------- + -------- +
| 拉丁1 | cp1252西欧| latin1_swedish_ci | 1 |
| 拉丁文2 | ISO 8859-2中欧| latin2_general_ci | 1 |
| 拉丁语5 | ISO 8859-9土耳其语| latin5_turkish_ci | 1 |
| 拉丁语7 | ISO 8859-13 Baltic | latin7_general_ci | 1 |
+ --------- + ----------------------------- + --------- ---------- + -------- +

SHOW CHARACTER SET 输出有以下列:

  • Charset

    字符集名称。

  • Description

    字符集的描述。

  • Default collation

    字符集的默认排序规则。

  • Maxlen

    存储一个字符所需的最大字节数。

filename 字符集是仅供内部使用; 因此, SHOW CHARACTER SET 不显示它。

INFORMATION_SCHEMA CHARACTER_SETS 表格中 也提供了字符集信息 请参见 第25.2节“INFORMATION_SCHEMA CHARACTER_SETS表”

13.7.6.4 SHOW COLLATION语法

显示收集
    [喜欢' pattern'| 在哪里expr]

此语句列出服务器支持的排序规则。 默认情况下,输出 SHOW COLLATION 包括所有可用的排序规则。 LIKE 子句(如果存在)指示要匹配的归类名称。 WHERE 子句可以使用更一般的条件来选择行,如 第25.42节“扩展到SHOW语句”中所述 例如:

MySQL的> SHOW COLLATION WHERE Charset = 'latin1';
+ ------------------- + --------- + ---- + --------- + ---- ------ + --------- +
| 整理| Charset | Id | 默认| 编译| Sortlen |
+ ------------------- + --------- + ---- + --------- + ---- ------ + --------- +
| latin1_german1_ci | 拉丁1 | 5 | | 是的| 1 |
| latin1_swedish_ci | 拉丁1 | 8 | 是的| 是的| 1 |
| latin1_danish_ci | 拉丁1 | 15 | | 是的| 1 |
| latin1_german2_ci | 拉丁1 | 31 | | 是的| 2 |
| latin1_bin | 拉丁1 | 47 | | 是的| 1 |
| latin1_general_ci | 拉丁1 | 48 | | 是的| 1 |
| latin1_general_cs | 拉丁1 | 49 | | 是的| 1 |
| latin1_spanish_ci | 拉丁1 | 94 | | 是的| 1 |
+ ------------------- + --------- + ---- + --------- + ---- ------ + --------- +

SHOW COLLATION 输出有以下列:

  • Collation

    整理名称。

  • Charset

    与排序规则关联的字符集的名称。

  • Id

    整理ID。

  • Default

    排序规则是否为其字符集的默认值。

  • Compiled

    字符集是否编译到服务器中。

  • Sortlen

    这与对字符集中表示的字符串进行排序所需的内存量有关。

若要查看每个字符集的默认排序规则,请使用以下语句。 Default 是一个保留字,所以要将其用作标识符,必须引用它:

MySQL的> SHOW COLLATION WHERE `Default` = 'Yes';
+ --------------------- + ---------- + ---- + --------- +  - --------- --------- + +
| 整理| Charset | Id | 默认| 编译| Sortlen |
+ --------------------- + ---------- + ---- + --------- +  - --------- --------- + +
| big5_chinese_ci | big5 | 1 | 是的| 是的| 1 |
| dec8_swedish_ci | dec8 | 3 | 是的| 是的| 1 |
| cp850_general_ci | cp850 | 4 | 是的| 是的| 1 |
| hp8_english_ci | hp8 | 6 | 是的| 是的| 1 |
| koi8r_general_ci | koi8r | 7 | 是的| 是的| 1 |
| latin1_swedish_ci | 拉丁1 | 8 | 是的| 是的| 1 |
...

INFORMATION_SCHEMA COLLATIONS 表格中 也提供了整理信息 请参见 第25.4节“INFORMATION_SCHEMA COLLATIONS表”

13.7.6.5 SHOW COLUMNS语法

显示[EXTENDED] [FULL] {COLUMNS | FIELDS}
    {FROM | IN} tbl_name
    [{FROM | IN} db_name]
    [喜欢' pattern'| 在哪里expr]

SHOW COLUMNS 显示有关给定表中列的信息。 它也适用于视图。 SHOW COLUMNS 仅显示您具有某些权限的列的信息。

MySQL的> SHOW COLUMNS FROM City;
+ ------------- + ---------- + ------ + ------ + --------- +  - --------------- +
| 领域| 输入| 空| 钥匙| 默认| 额外的|
+ ------------- + ---------- + ------ + ------ + --------- +  - --------------- +
| ID | int(11)| 没有| PRI | NULL | auto_increment |
| 名称| char(35)| 没有| | | |
| CountryCode | char(3)| 没有| MUL | | |
| 区| char(20)| 没有| | | |
| 人口| int(11)| 没有| | 0 | |
+ ------------- + ---------- + ------ + ------ + --------- +  - --------------- +

语法 的替代方法 这两个陈述是等价的: tbl_name FROM db_name db_name.tbl_name

从mytable FROM mydb显示列;
显示来自mydb.mytable的列;

可选 EXTENDED 关键字使输出包含有关MySQL内部使用且用户无法访问的隐藏列的信息。

可选 FULL 关键字使输出包含列排序规则和注释,以及您对每列的权限。

LIKE 子句(如果存在)指示要匹配的列名称。 WHERE 子句可以使用更一般的条件来选择行,如 第25.42节“扩展到SHOW语句”中所述

数据类型可能与您希望它们基于 CREATE TABLE 语句 的数据类型不同, 因为MySQL有时会在您创建或更改表时更改数据类型。 发生这种情况的条件在 第13.1.20.8节“无声列规范更改”中描述

SHOW COLUMNS 为每个表列显示以下值:

  • Field

    列的名称。

  • Type

    列数据类型。

  • Collation

    非二进制字符串列或 NULL 其他列 的排序规则 仅当您使用 FULL 关键字时 才会显示此值

  • Null

    列可空性。 该值 YES 是否 NULL 可以将值存储在列中, NO 如果不存在。

  • Key

    列是否已编入索引:

    • 如果 Key 为空,则列不会被索引,也不会仅作为多列非唯一索引中的辅助列索引。

    • 如果 Key PRI ,则列是a PRIMARY KEY 或多列中的列之一 PRIMARY KEY

    • 如果 Key UNI ,则列是 UNIQUE 索引 的第一列 UNIQUE 索引允许多个 NULL 值,但您可以 NULL 通过检查 Null 字段 来判断列是否允许 。)

    • 如果 Key MUL ,则该列是非唯一索引的第一列,其中在列中允许多次出现给定值。

    如果超过一个 Key 值适用于表中给定的列, Key 显示了一个具有最高优先级,顺序 PRI UNI MUL

    UNIQUE 索引可被显示为 PRI ,如果它不能包含 NULL 值并没有 PRIMARY KEY 在表中。 UNIQUE 索引可能会显示为 MUL 如果若干列形成复合 UNIQUE 索引; 虽然列的组合是唯一的,但每列仍然可以保存给定值的多次出现。

  • Default

    列的默认值。 这是 NULL 因为列具有显式默认值 NULL ,或者列定义包含无 DEFAULT 子句。

  • Extra

    有关给定列的任何其他可用信息。 在这些情况下,该值是非空的:

    • auto_increment 对于具有该 AUTO_INCREMENT 属性的

    • on update CURRENT_TIMESTAMP for TIMESTAMP DATETIME 具有该 ON UPDATE CURRENT_TIMESTAMP 属性的

    • VIRTUAL GENERATED 或者 VIRTUAL STORED 用于生成的列。

    • DEFAULT_GENERATED 对于具有表达式默认值的列。

  • Privileges

    您对该列的权限。 仅当您使用 FULL 关键字时 才会显示此值

  • Comment

    列定义中包含的任何注释。 仅当您使用 FULL 关键字时 才会显示此值

表格列表信息也可从 INFORMATION_SCHEMA COLUMNS 表格中获得。 请参见 第25.6节“INFORMATION_SCHEMA COLUMNS表” 有关隐藏列的扩展信息仅可使用 SHOW EXTENDED COLUMNS ; 它不能从 COLUMNS 表中 获得

您可以使用 mysqlshow db_name tbl_name 命令 列出表的列

DESCRIBE 声明提供类似的信息 SHOW COLUMNS 请参见 第13.8.1节“DESCRIBE语法”

SHOW CREATE TABLE SHOW TABLE STATUS SHOW INDEX 语句还提供有关表的信息。 请参见 第13.7.6节“显示语法”

13.7.6.6 SHOW CREATE DATABASE语法

SHOW CREATE {DATABASE | SCHEMA} [如果不存在]db_name

显示 CREATE DATABASE 创建指定数据库 语句。 如果 SHOW 语句包含一个 IF NOT EXISTS 子句,则输出也包含这样的子句。 SHOW CREATE SCHEMA 是...的同义词 SHOW CREATE DATABASE

MySQL的> SHOW CREATE DATABASE test\G
*************************** 1。排******************** *******
       数据库:测试
创建数据库:CREATE DATABASE`test` / *!40100 DEFAULT CHARACTER SET utf8mb4 
                 COLLATE utf8mb4_0900_ai_ci * / / *!80014 DEFAULT ENCRYPTION ='N'* /

MySQL的> SHOW CREATE SCHEMA test\G
*************************** 1。排******************** *******
       数据库:测试
创建数据库:CREATE DATABASE`test` / *!40100 DEFAULT CHARACTER SET utf8mb4 
                 COLLATE utf8mb4_0900_ai_ci * / / *!80014 DEFAULT ENCRYPTION ='N'* /   

SHOW CREATE DATABASE 根据 sql_quote_show_create 选项 的值引用表名和列名 请参见 第5.1.8节“服务器系统变量”

13.7.6.7 SHOW CREATE EVENT语法

显示创建事件 event_name

此语句显示 CREATE EVENT 重新创建给定事件所需 语句。 它需要 EVENT 从中显示事件的数据库 权限。 例如(使用 e_daily 第13.7.6.18节“SHOW EVENTS语法”中 定义并随后更改 的相同事件 ):

MySQL的> SHOW CREATE EVENT myschema.e_daily\G
*************************** 1。排******************** *******
               事件:e_daily
            sql_mode:ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,
                      NO_ZERO_IN_DATE,NO_ZERO_DATE,
                      ERROR_FOR_DIVISION_BY_ZERO,
                      NO_ENGINE_SUBSTITUTION
           time_zone:SYSTEM
        创建事件:CREATE DEFINER =`jon` @`ghidora` EVENT`e_daily`
                        每天安排一次
                        STARTS CURRENT_TIMESTAMP + INTERVAL 6小时
                        完成不保留
                        ENABLE
                        评论'然后保存会话总数
                                每天清理桌子'
                        开始吧
                          INSERT INTO site_activity.totals(时间,总计)
                            SELECT CURRENT_TIMESTAMP,COUNT(*)
                              来自site_activity.sessions;
                          从site_activity.sessions中删除;
                        结束
character_set_client:utf8mb4
collat​​ion_connection:utf8mb4_0900_ai_ci
  数据库整理:utf8mb4_0900_ai_ci

character_set_client character_set_client 创建事件时系统变量 的会话值 collation_connection collation_connection 创建事件时系统变量 的会话值 Database Collation 是与事件关联的数据库的排序规则。

输出反映了事件( ENABLE 的当前状态, 而不是创建它的状态。

13.7.6.8 SHOW CREATE FUNCTION语法

显示创造功能 func_name

此语句与 SHOW CREATE PROCEDURE 存储函数 类似 请参见 第13.7.6.9节“显示创建过程语法”

13.7.6.9 SHOW CREATE PROCEDURE语法

显示创建过程 proc_name

该语句是MySQL扩展。 它返回可用于重新创建命名存储过程的确切字符串。 类似的语句 SHOW CREATE FUNCTION 显示有关存储函数的信息(请参见 第13.7.6.8节“显示函数语法” )。

要使用任一语句,您必须具有全局 SELECT 特权。

MySQL的> SHOW CREATE PROCEDURE test.simpleproc\G
*************************** 1。排******************** *******
           过程:simpleproc
            sql_mode:ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,
                      NO_ZERO_IN_DATE,NO_ZERO_DATE,
                      ERROR_FOR_DIVISION_BY_ZERO,
                      NO_ENGINE_SUBSTITUTION
    创建过程:CREATE PROCEDURE`simpleproc`(OUT param1 INT)
                      开始
                      SELECT COUNT(*)INTO param1 FROM t;
                      结束
character_set_client:utf8mb4
collat​​ion_connection:utf8mb4_0900_ai_ci
  数据库整理:utf8mb4_0900_ai_ci

MySQL的> SHOW CREATE FUNCTION test.hello\G
*************************** 1。排******************** *******
            功能:你好
            sql_mode:ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,
                      NO_ZERO_IN_DATE,NO_ZERO_DATE,
                      ERROR_FOR_DIVISION_BY_ZERO,
                      NO_ENGINE_SUBSTITUTION
     创建函数:CREATE FUNCTION`hello`(s CHAR(20))
                      返回char(50)CHARSET utf8mb4
                      返回CONCAT('你好,',s,'!')
character_set_client:utf8mb4
collat​​ion_connection:utf8mb4_0900_ai_ci
  数据库整理:utf8mb4_0900_ai_ci

character_set_client character_set_client 创建例程时系统变量 的会话值 collation_connection collation_connection 创建例程时系统变量 的会话值 Database Collation 是与例程关联的数据库的排序规则。

13.7.6.10 SHOW CREATE TABLE语法

显示创建表 tbl_name

显示 CREATE TABLE 创建命名表 语句。 要使用此语句,您必须拥有该表的某些权限。 此声明也适用于视图。

MySQL的> SHOW CREATE TABLE t\G
*************************** 1。排******************** *******
       表:t
创建表:CREATE TABLE`t`(
  `id` int(11)NOT NULL AUTO_INCREMENT,
  `s` char(60)DEFAULT NULL,
  PRIMARY KEY(`id`)
)ENGINE = InnoDB DEFAULT CHARSET = utf8mb4

从MySQL 8.0.16开始,MySQL实现 CHECK 约束并 SHOW CREATE TABLE 显示它们。 所有 CHECK 约束都显示为表约束。 也就是说, CHECK 最初指定为列定义一部分的约束显示为单独的子句,而不是列定义的一部分。 例:

MySQL的> CREATE TABLE t1 (
         i1 INT CHECK (i1 <> 0),      -- column constraint
         i2 INT,
         CHECK (i2 > i1),             -- table constraint
         CHECK (i2 <> 0) NOT ENFORCED -- table constraint, not enforced
       );

MySQL的> SHOW CREATE TABLE t1\G
*************************** 1。排******************** *******
       表:t1
创建表:CREATE TABLE`t1`(
  `i1` int(11)DEFAULT NULL,
  `i2` int(11)DEFAULT NULL,
  约束`t1_chk_1`检查((``i1` <> 0)),
  约束`t1_chk_2`检查((``i2`>`i1`)),
  约束`t1_chk_3`检查((``i2` <> 0))/ *!80016未强制执行* /
)ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci

SHOW CREATE TABLE 根据 sql_quote_show_create 选项 的值引用表名和列名 请参见 第5.1.8节“服务器系统变量”

有关 CREATE TABLE MySQL 如何 存储语句的 信息 ,请参见 第13.1.20.1节“CREATE TABLE语句保留”

13.7.6.11 SHOW CREATE TRIGGER语法

显示创建触发器 trigger_name

此语句显示 CREATE TRIGGER 创建命名触发器 语句。 此语句需要 TRIGGER 与触发器关联的表 特权。

MySQL的> SHOW CREATE TRIGGER ins_sum\G
*************************** 1。排******************** *******
               触发:ins_sum
              sql_mode:ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,
                        NO_ZERO_IN_DATE,NO_ZERO_DATE,
                        ERROR_FOR_DIVISION_BY_ZERO,
                        NO_ENGINE_SUBSTITUTION
SQL原声明:CREATE DEFINER =`me` @`localhost`TRIGGER`ins_sum`
                        在插入`帐户'之前
                        每个行设置@sum = @sum + NEW.amount
  character_set_client:utf8mb4
  collat​​ion_connection:utf8mb4_0900_ai_ci
    数据库整理:utf8mb4_0900_ai_ci
               创建时间:2018-08-08 10:10:12.61

SHOW CREATE TRIGGER 输出有以下列:

  • Trigger :触发​​器名称。

  • sql_mode :触发​​器执行时生效的SQL模式。

  • SQL Original Statement CREATE TRIGGER 定义触发器 语句。

  • character_set_client character_set_client 创建触发器时系统变量 的会话值

  • collation_connection collation_connection 创建触发器时系统变量 的会话值

  • Database Collation :与触发器关联的数据库的排序规则。

  • Created :创建触发器的日期和时间。 这是 TIMESTAMP(2) 触发器 值(以百分之几秒为单位)。

INFORMATION_SCHEMA TRIGGERS 表格中 也提供了触发信息 请参见 第25.34节“INFORMATION_SCHEMA TRIGGERS表”

13.7.6.12 SHOW CREATE USER语法

显示创建用户 user

此语句显示 CREATE USER 创建命名用户 语句。 如果用户不存在,则会发生错误。 除了查看当前用户的信息外, 该语句还需要 系统数据库 SELECT 权限 mysql 对于当前用户, 需要系统表 SELECT 权限才能 mysql.user IDENTIFIED AS 子句中 显示密码哈希 ; 否则,哈希显示为 <secret>

要为帐户命名,请使用 第6.2.4节“指定帐户名称”中 所述的格式 帐户名的主机名部分(如果省略)默认为 '%' 还可以指定 CURRENT_USER CURRENT_USER() 引用与当前会话相关联的帐户。

IDENTIFIED WITH 输出子句中 显示的密码哈希值 SHOW CREATE USER 可能包含对终端显示和其他环境有不利影响的不可打印字符。 启用 print_identified_with_as_hex 系统变量(从MySQL 8.0.17开始提供)会导致 SHOW CREATE USER 将此类哈希值显示为十六进制字符串而不是常规字符串文字。 不包含不可打印字符的哈希值仍显示为常规字符串文字,即使启用了此变量也是如此。

mysql> CREATE USER 'u1'@'localhost' IDENTIFIED BY 'secret';
mysql> SET print_identified_with_as_hex = ON;
mysql>SHOW CREATE USER 'u1'@'localhost'\G
*************************** 1。排******************** *******
u1 @ localhost的CREATE USER:CREATE USER'u1'@'localhost'
通过'caching_sha2_password'识别
AS 0x244124303035240C7745603626313D613C4C10633E0A104B1E14135A544A7871567245614F4872344643546336546F624F6C7861326932752F45622F4F4732735975576​​27139
要求无密码存款违约帐户解锁
密码历史默认密码重新使用间隔默认值
密码要求当前默认值

要显示授予帐户的权限,请使用该 SHOW GRANTS 语句。 请参见 第13.7.6.21节“显示GRANTS语法”

13.7.6.13 SHOW CREATE VIEW语法

显示创建视图 view_name

此语句显示 CREATE VIEW 创建命名视图 语句。

MySQL的> SHOW CREATE VIEW v\G
*************************** 1。排******************** *******
                查看:v
         创建视图:CREATE ALGORITHM = UNDEFINED
                      DEFINER =`bob` @`localhost`
                      SQL安全定义视图
                      `v` AS选择1 AS`a`,2 AS`b`
character_set_client:utf8mb4
collat​​ion_connection:utf8mb4_0900_ai_ci

character_set_client character_set_client 创建视图时系统变量 的会话值 collation_connection collation_connection 创建视图时系统变量 的会话值

使用 SHOW CREATE VIEW 需要 SHOW VIEW 特权和 SELECT 相关视图 特权。

查询信息也可从 INFORMATION_SCHEMA VIEWS 表中获得。 请参见 第25.36节“INFORMATION_SCHEMA VIEWS表”

MySQL允许您使用不同的 sql_mode 设置来告诉服务器要支持的SQL语法的类型。 例如,您可以使用 ANSI SQL模式来确保MySQL || 在查询中 正确解释标准SQL连接运算符double bar( )。 如果您随后创建了一个连接项目的视图,您可能会担心将 sql_mode 设置 更改为 不同的值 ANSI 可能会导致视图无效。 但这种情况并非如此。 无论你如何编写视图定义,MySQL总是以规范的形式存储它。 这是一个示例,显示服务器如何将双条串联运算符更改为a CONCAT() 功能:

MySQL的> SET sql_mode = 'ANSI';
查询正常,0行受影响(0.00秒)

MySQL的> CREATE VIEW test.v AS SELECT 'a' || 'b' as col1;
查询OK,0行受影响(0.01秒)

MySQL的> SHOW CREATE VIEW test.v\G
*************************** 1。排******************** *******
                查看:v
         创建视图:创建视图“v”AS选择连续('a','b')AS“col1”
...
1排(0.00秒)

以规范形式存储视图定义的优点是,稍后对值进行的更改 sql_mode 不会影响视图的结果。 然而,另一个后果是 SELECT 服务器从定义中删除 之前的注释

13.7.6.14 SHOW DATABASES语法

SHOW {DATABASES | SCHEMAS}
    [喜欢' pattern'| 在哪里expr]

SHOW DATABASES 列出MySQL服务器主机上的数据库。 SHOW SCHEMAS 是...的同义词 SHOW DATABASES LIKE 子句(如果存在)指示要匹配的数据库名称。 WHERE 子句可以使用更一般的条件来选择行,如 第25.42节“扩展到SHOW语句”中所述

您只能看到具有某种特权的数据库,除非您拥有全局 SHOW DATABASES 特权。 您也可以使用 mysqlshow 命令 获取此列表

如果使用该 --skip-show-database 选项 启动服务器,则 除非您具有该 SHOW DATABASES 权限, 否则根本不能使用此语句

MySQL将数据库实现为数据目录中的目录,因此该语句只列出该位置中的目录。 但是,输出可能包括与实际数据库不对应的目录名称。

INFORMATION_SCHEMA SCHEMATA 表中 还提供了数据库信息 请参见 第25.24节“INFORMATION_SCHEMA SCHEMATA表”

警告

因为任何静态全局特权被认为是所有数据库的特权,任何静态全局特权使用户能够看到所有的数据库名称 SHOW DATABASES 或通过检查 SCHEMATA INFORMATION_SCHEMA ,除了已经在通过局部撤销数据库级别被限制的数据库。

13.7.6.15 SHOW ENGINE语法

SHOW ENGINE engine_name{STATUS | MUTEX}

SHOW ENGINE 显示有关存储引擎的操作信息。 它需要 PROCESS 特权。 该声明有以下变体:

显示发动机创新状态
SHOW ENGINE INNODB MUTEX
SHOW ENGINE PERFORMANCE_SCHEMA状态

SHOW ENGINE INNODB STATUS 显示标准 InnoDB 监视器中有关 InnoDB 存储引擎 状态的 大量信息 有关标准监视器和其他 InnoDB 监视器的信息 InnoDB ,请参见 第15.16节“InnoDB监视器”

SHOW ENGINE INNODB MUTEX 显示 InnoDB 互斥锁 rw-lock 统计信息。

注意

InnoDB 还可以使用 性能架构 监视互斥锁和rwlock 请参见 第15.15.2节“使用性能模式监视InnoDB Mutex等待”

使用以下选项动态配置互斥锁统计信息收集:

  • 要启用互斥锁统计信息的收集,请运行:

    SET GLOBAL innodb_monitor_enable ='latch';
  • 要重置互斥锁统计信息,请运行:

    SET GLOBAL innodb_monitor_reset ='latch';
  • 要禁用互斥锁统计信息的收集,请运行:

    SET GLOBAL innodb_monitor_disable ='latch';

SHOW ENGINE INNODB MUTEX 也可以通过设置 innodb_monitor_enable='all' 或通过设置禁用 来启用 互斥锁统计信息的收集 innodb_monitor_disable='all'

SHOW ENGINE INNODB MUTEX 输出有以下列:

  • Type

    永远 InnoDB

  • Name

    对于互斥锁,该 Name 字段仅报告互斥锁名称。 对于rwlock,该 Name 字段报告实现rwlock的源文件,以及创建rwlock的文件中的行号。 行号特定于您的MySQL版本。

  • Status

    互斥状态。 此字段报告旋转,等待和调用的数量。 InnoDB 不报告 在外部实现的低级操作系统互斥锁的统计信息

    • spins 表示旋转次数。

    • waits 表示互斥锁等待的数量。

    • calls 表示请求互斥锁的次数。

SHOW ENGINE INNODB MUTEX 跳过 互斥 RW-锁 缓冲池 块,作为输出的量可以在一个大缓冲池系统压倒性的。 (每个16K缓冲池块中有一个互斥锁和一个rw锁,每GB有65,536个块。) SHOW ENGINE INNODB MUTEX 也没有列出从未等待的任何互斥锁或rw锁( os_waits=0 )。 因此, SHOW ENGINE INNODB MUTEX 仅显示有关已导致至少一个OS级别 等待 的缓冲池外部的互斥锁和rw锁定的信息

使用 SHOW ENGINE PERFORMANCE_SCHEMA STATUS 检查绩效模式的代码的内部操作:

MySQL的> SHOW ENGINE PERFORMANCE_SCHEMA STATUS\G
...
*************************** 3。排******************** *******
  输入:performance_schema
  名称:events_waits_history.size
状态:76
****************************排******************** *******
  输入:performance_schema
  名称:events_waits_history.count
状态:10000
****************************排******************** *******
  输入:performance_schema
  名称:events_waits_history.memory
状态:760000
...
*************************** 57.排******************** *******
  输入:performance_schema
  名称:performance_schema.memory
状态:26459600
...

此语句旨在帮助DBA了解不同性能模式选项对内存要求的影响。

Name 值由两部分组成,分别命名内部缓冲区和缓冲区属性。 解释缓冲区名称如下:

  • 未作为表公开的内部缓冲区在括号内命名。 例子: (pfs_cond_class).size (pfs_mutex_class).memory

  • performance_schema 数据库中 作为表公开的内部缓冲区以表的 形式命名,没有括号。 例子: events_waits_history.size mutex_instances.count

  • 适用于整体性能模式的值以 performance_schema 开头 示例: performance_schema.memory

缓冲区属性具有以下含义:

  • size 是实现使用的内部记录的大小,例如表中行的大小。 size 值无法更改。

  • count 是内部记录的数量,例如表中的行数。 count 可以使用“性能架构”配置选项更改值。

  • 对于表, tbl_name.memory 是产品 size count 对于整体性能模式, performance_schema.memory 是所有使用的内存的总和(所有其他 memory 的总和 )。

在某些情况下,Performance Schema配置参数与 SHOW ENGINE 之间存在直接关系 例如, events_waits_history_long.count 对应于 performance_schema_events_waits_history_long_size 在其他情况下,这种关系更复杂。 例如, events_waits_history.count 对应于 performance_schema_events_waits_history_size (每个线程的行数)乘以 performance_schema_max_thread_instances (线程数)。

SHOW ENGINE NDB状态。  如果服务器 NDB 启用 存储引擎,则 SHOW ENGINE NDB STATUS 显示群集状态信息,例如连接的数据节点数,群集连接字符串和群集二进制日志时期,以及MySQL服务器连接到服务器时创建的各种群集API对象的计数。簇。 此语句的示例输出如下所示:

MySQL的> SHOW ENGINE NDB STATUS;
+ ------------ + ------------ + ------------ -------------------------------------- +
| 输入| 名称| 状态|
+ ------------ + ------------ + ------------ -------------------------------------- +
| ndbcluster | 连接| cluster_node_id = 7,
  connected_host = 198.51.100.103,connected_port = 1186,number_of_data_nodes = 4,
  number_of_ready_data_nodes = 3,connect_count = 0 |
| ndbcluster | NdbTransaction | created = 6,free = 0,sizeof = 212 |
| ndbcluster | NdbOperation | created = 8,free = 8,sizeof = 660 |
| ndbcluster | NdbIndexScanOperation | created = 1,free = 1,sizeof = 744 |
| ndbcluster | NdbIndexOperation | created = 0,free = 0,sizeof = 664 |
| ndbcluster | NdbRecAttr | created = 1285,free = 1285,sizeof = 60 |
| ndbcluster | NdbApiSignal | created = 16,free = 16,sizeof = 136 |
| ndbcluster | NdbLabel | created = 0,free = 0,sizeof = 196 |
| ndbcluster | NdbBranch | created = 0,free = 0,sizeof = 24 |
| ndbcluster | NdbSubroutine | created = 0,free = 0,sizeof = 68 |
| ndbcluster | NdbCall | created = 0,free = 0,sizeof = 16 |
| ndbcluster | NdbBlob | created = 1,free = 1,sizeof = 264 |
| ndbcluster | NdbReceiver | created = 4,free = 0,sizeof = 68 |
| ndbcluster | binlog | latest_epoch = 155467,latest_trans_epoch = 148126,
  latest_received_binlog_epoch = 0,latest_handled_binlog_epoch = 0,
  latest_applied_binlog_epoch = 0 |
+ ------------ + ------------ + ------------ -------------------------------------- +

Status 每个行中 列分别提供有关MySQL服务器与群集的连接以及群集二进制日志状态的信息。 Status 信息是在逗号分隔的组的名称/值对的形式。

connection 行的 Status 列包含以下表中描述的名称/值对。

名称
cluster_node_id 集群中MySQL服务器的节点ID
connected_host MySQL服务器所连接的集群管理服务器的主机名或IP地址
connected_port MySQL服务器用于连接管理服务器的端口( connected_host
number_of_data_nodes 为群集配置的数据节点数(即 [ndbd] 群集 config.ini 文件中
number_of_ready_data_nodes 群集中实际运行的数据节点数
connect_count mysqld 已连接或重新连接到群集数据节点的次数

binlog 行的 Status 列包含与NDB群集复制信息。 它包含的名称/值对在下表中描述。

名称
latest_epoch 最近在这个MySQL服务器上运行的最新纪元(即服务器上运行的最新事务的序列号)
latest_trans_epoch 群集的数据节点处理的最新纪元
latest_received_binlog_epoch 二进制日志线程收到的最新纪元
latest_handled_binlog_epoch 二进制日志线程处理的最新纪元(用于写入二进制日志)
latest_applied_binlog_epoch 最近的epoch实际写入二进制日志

有关 更多信息 请参见 第22.6节“NDB群集复制”

其输出中剩余的行 SHOW ENGINE NDB STATUS 最有可能在监视群集时非常有用,在此列出 Name

  • NdbTransaction NdbTransaction 已创建 对象 的数量和大小 一个 NdbTransaction 每次创建一个表模式操作(例如 CREATE TABLE ALTER TABLE )上执行 NDB 表。

  • NdbOperation NdbOperation 已创建 对象 的数量和大小

  • NdbIndexScanOperation NdbIndexScanOperation 已创建 对象 的数量和大小

  • NdbIndexOperation NdbIndexOperation 已创建 对象 的数量和大小

  • NdbRecAttr NdbRecAttr 已创建 对象 的数量和大小 通常,每次SQL节点执行数据操作语句时都会创建其中一个。

  • NdbBlob NdbBlob 已创建 对象 的数量和大小 一个 NdbBlob 是对于涉及每个新创建的操作 BLOB 在列 NDB 表。

  • NdbReceiver NdbReceiver 已创建 的任何 对象 的数量和大小 在数 created 列是相同的数据节点,其MySQL服务器具有连接在集群中的数量。

注意

SHOW ENGINE NDB STATUS 如果 NDB MySQL客户端访问运行此语句的SQL节点在当前会话期间 未执行涉及 表的 操作,则返回空结果

13.7.6.16 SHOW ENGINES语法

显示[存储]发动机

SHOW ENGINES 显示有关服务器存储引擎的状态信息。 这对于检查是否支持存储引擎或查看默认引擎是什么特别有用。

有关MySQL存储引擎的信息,请参阅 第15章, InnoDB存储引擎 第16章, 备用存储引擎

MySQL的> SHOW ENGINES\G
*************************** 1。排******************** *******
      引擎:存档
     支持:是的
     评论:归档存储引擎
交易:NO
          XA:没有
  保存点:没有
*************************** 2.排******************** *******
      发动机:BLACKHOLE
     支持:是的
     评论:/ dev / null存储引擎(你写的东西都消失了)
交易:NO
          XA:没有
  保存点:没有
*************************** 3。排******************** *******
      发动机:MRG_MYISAM
     支持:是的
     评论:收集相同的MyISAM表
交易:NO
          XA:没有
  保存点:没有
****************************排******************** *******
      发动机:FEDERATED
     支持:没有
     评论:联合MySQL存储引擎
交易:NULL
          XA:NULL
  保存点:NULL
****************************排******************** *******
      引擎:MyISAM
     支持:是的
     评论:MyISAM存储引擎
交易:NO
          XA:没有
  保存点:没有
*************************** 6.排******************** *******
      引擎:PERFORMANCE_SCHEMA
     支持:是的
     评论:性能架构
交易:NO
          XA:没有
  保存点:没有
*************************** 7.排******************** *******
      引擎:InnoDB
     支持:默认
     注释:支持事务,行级锁定和外键
交易:YES
          XA:是的
  保存点:是
*************************** 8.排******************** *******
      发动机:记忆
     支持:是的
     注释:基于哈希,存储在内存中,对临时表有用
交易:NO
          XA:没有
  保存点:没有
*************************** 9。排******************** *******
      引擎:CSV
     支持:是的
     评论:CSV存储引擎
交易:NO
          XA:没有
  保存点:没有

输出 SHOW ENGINES 可能会根据使用的MySQL版本和其他因素而有所不同。

SHOW ENGINES 输出有以下列:

  • Engine

    存储引擎的名称。

  • Support

    服务器对存储引擎的支持级别,如下表所示。

    含义
    YES 引擎受支持且处于活动状态
    DEFAULT 比如 YES ,加上这是默认引擎
    NO 不支持引擎
    DISABLED 引擎受支持但已被禁用

    NO 意味着在不支持引擎的情况下编译服务器,因此无法在运行时启用它。

    DISABLED 发生 的值 可能是因为服务器是使用禁用引擎的选项启动的,或者因为并未提供启用它所需的所有选项。 在后一种情况下,错误日志应包含指示禁用该选项的原因。 请参见 第5.4.2节“错误日志”

    您可能还会看到 DISABLED 存储引擎,如果服务器已编译为支持它,但是启动了一个 选项。 对于 存储引擎, 表示服务器是在支持NDB Cluster的情况下编译的,但未使用该 选项 启动 --skip-engine_name NDB DISABLED --ndbcluster

    所有MySQL服务器都支持 MyISAM 表。 无法禁用 MyISAM

  • Comment

    存储引擎的简要说明。

  • Transactions

    存储引擎是否支持事务。

  • XA

    存储引擎是否支持XA事务。

  • Savepoints

    存储引擎是否支持保存点。

INFORMATION_SCHEMA ENGINES 表中 还提供了存储引擎信息 请参见 第25.9节“INFORMATION_SCHEMA ENGINES表”

13.7.6.17显示错误语法

显示错误[限制[ offset,]row_count ]
显示计数(*)错误

SHOW ERRORS 是一个类似于的诊断语句 SHOW WARNINGS ,除了它仅显示错误信息,而不是错误,警告和注释。

LIMIT 子句的语法与 SELECT 语句 相同 请参见 第13.2.10节“SELECT语法”

SHOW COUNT(*) ERRORS 语句显示错误数。 您还可以从 error_count 变量中 检索此数字

显示计数(*)错误;
SELECT @@ error_count;

SHOW ERRORS error_count 仅适用于错误,而不是警告或注释。 在其他方面,它们与 SHOW WARNINGS 类似 warning_count 特别是, SHOW ERRORS 不能显示超过 max_error_count 消息的信息,并且 error_count 可能超过 max_error_count 错误数量 超过的值 max_error_count

有关更多信息,请参见 第13.7.6.40节“显示警告语法”

13.7.6.18显示事件语法

展示活动
    [{FROM | IN}schema_name ]
    [喜欢' pattern'| 在哪里expr]

此语句显示有关事件管理器事件的信息,这将在 第24.4节“使用事件调度程序”中讨论 它需要 EVENT 从中显示事件的数据库 特权。

在最简单的形式中, SHOW EVENTS 列出当前模式中的所有事件:

MySQL的> SELECT CURRENT_USER(), SCHEMA();
+ ---------------- + ---------- +
| CURRENT_USER()| SCHEMA()|
+ ---------------- + ---------- +
| jon @ ghidora | myschema |
+ ---------------- + ---------- +
1排(0.00秒)

MySQL的> SHOW EVENTS\G
*************************** 1。排******************** *******
                  Db:myschema
                姓名:e_daily
             定义者:jon @ ghidora
           时区:SYSTEM
                类型:RECURRING
          执行at:NULL
      区间值:1
      间隔字段:DAY
              开始时间:2018-08-08 11:06:34
                结束:NULL
              状态:已启用
          发起人:1
character_set_client:utf8mb4
collat​​ion_connection:utf8mb4_0900_ai_ci
  数据库整理:utf8mb4_0900_ai_ci

要查看特定模式的事件,请使用该 FROM 子句。 例如,要查看 test 模式的 事件 ,请使用以下语句:

显示测试事件;

LIKE 子句(如果存在)指示要匹配的事件名称。 WHERE 子句可以使用更一般的条件来选择行,如 第25.42节“扩展到SHOW语句”中所述

SHOW EVENTS 输出有以下列:

  • Db

    事件所属的架构(数据库)的名称。

  • Name

    事件的名称。

  • Definer

    格式 创建事件的用户的帐户 'user_name'@'host_name'

  • Time zone

    事件时区,用于调度事件的时区,在执行时在事件中生效。 默认值为 SYSTEM

  • Type

    事件重复类型, ONE TIME (瞬态)或 RECURRING (重复)。

  • Execute At

    对于一次性事件,这是在 用于创建事件 语句 DATETIME AT 子句中 指定 CREATE EVENT ,或者 ALTER EVENT 是修改事件 的最后一个 语句中 指定 此列中显示的值反映 INTERVAL 了事件 AT 子句中 包含 的任何 的加或减 例如,如果使用创建事件 ON SCHEDULE AT CURRENT_TIMESTAMP + '1:6' DAY_HOUR ,并且事件是在2018-02-09 14:05:30创建的,则此列中显示的值将为 '2018-02-10 20:05:30' 如果事件的时间由一个 EVERY 条款而不是 一个 条款 决定 AT 子句(即,如果事件是重复出现的),则此列的值为 NULL

  • Interval Value

    对于重复事件,在事件执行之间等待的间隔数。 对于瞬态事件,此列的值始终为 NULL

  • Interval Field

    用于重复事件在重复之前等待的间隔的时间单位。 对于瞬态事件,此列的值始终为 NULL

  • Starts

    重复活动的开始日期和时间。 这将显示为 DATETIME 值, NULL 如果没有为事件定义开始日期和时间 则显示该 对于瞬态事件,此列始终为 NULL 对于定义包含 STARTS 子句 的定期事件 ,此列包含相应的 DATETIME 值。 Execute At 列一样,此值可解析所使用的任何表达式。 如果没有 STARTS 影响事件发生时间的条款,则此列为 NULL

  • Ends

    对于定义包含 ENDS 子句 的定期事件 ,此列包含相应的 DATETIME 值。 Execute At 列一样,此值可解析所使用的任何表达式。 如果没有 ENDS 影响事件发生时间的条款,则此列为 NULL

  • Status

    事件状态。 其中一个 ENABLED DISABLED SLAVESIDE_DISABLED SLAVESIDE_DISABLED 表示事件的创建发生在充当复制主服务器的另一个MySQL服务器上并复制到充当从服务器的当前MySQL服务器,但该事件当前未在从服务器上执行。 有关更多信息,请参见 第17.4.1.16节“调用调用的功能” 信息。

  • Originator

    创建事件的MySQL服务器的服务器ID; 用于复制。 ALTER EVENT 如果在主服务器上执行,则 可以将该值更新 为发生该语句的服务器的服务器ID。 默认值为0。

  • character_set_client

    character_set_client 创建事件时系统变量 的会话值

  • collation_connection

    collation_connection 创建事件时系统变量 的会话值

  • Database Collation

    与事件关联的数据库的排序规则。

有关 SLAVESIDE_DISABLED Originator 列的 更多信息 ,请参见 第17.4.1.16节“调用调用的功能”

显示的 SHOW EVENTS 时间在事件时区中给出,如 第24.4.4节“事件元数据”中所述

活动信息也可从 INFORMATION_SCHEMA EVENTS 表格中获得。 请参见 第25.10节“INFORMATION_SCHEMA事件表”

事件操作语句未显示在输出中 SHOW EVENTS 使用 SHOW CREATE EVENT INFORMATION_SCHEMA EVENTS 表。

13.7.6.19 SHOW FUNCTION CODE语法

显示功能代码 func_name

此语句与 SHOW PROCEDURE CODE 存储函数 类似 请参见 第13.7.6.27节“显示过程代码语法”

13.7.6.20显示功能状态语法

显示功能状态
    [喜欢' pattern'| 在哪里expr]

此语句与 SHOW PROCEDURE STATUS 存储函数 类似 请参见 第13.7.6.28节“显示过程状态语法”

13.7.6.21 SHOW GRANTS语法

显示资助
    [为user_or_role
        [使用role[,role] ...]]

user_or_role:{
     user
  |role
}

此语句以 GRANT 必须执行以复制权限和角色分配 语句 形式显示分配给MySQL用户帐户或角色 的权限和角色。

注意

要显示MySQL帐户的非特权信息,请使用该 SHOW CREATE USER 语句。 请参见 第13.7.6.12节“显示创建用户语法”

SHOW GRANTS 需要 系统数据库 SELECT 权限 mysql ,除了显示当前用户的权限和角色。

要为该帐户或角色命名 SHOW GRANTS ,请使用与该 GRANT 语句 相同的格式 (例如 'jeffrey'@'localhost' ):

MySQL的> SHOW GRANTS FOR 'jeffrey'@'localhost';
+ ------------------------------------------------- ----------------- +
| 为jeffrey @ localhost提供补助金
+ ------------------------------------------------- ----------------- +
| 授予*。*给`jeffrey` @`localhost` |
| GRANT SELECT,INSERT,UPDATE on`db1`。* to`jeffrey` @`localhost` |
+ ------------------------------------------------- ----------------- +

主机部分(如果省略)默认为 '%' 有关指定帐户和角色名称的其他信息,请参见 第6.2.4节“指定帐户名” 第6.2.5节“指定角色名称”

要显示授予当前用户(用于连接服务器的帐户)的权限,可以使用以下任何语句:

显示资助;
为CURRENT_USER提供资助;
显示CURRENT_USER()的资助金额;

如果 SHOW GRANTS FOR CURRENT_USER (或任何等效语法)在定义上下文中使用,例如在使用定义者而不是调用者权限执行的存储过程中,则显示的授权是定义者而不是调用者的授权。

在MySQL 8.0中,与之前的系列相比, SHOW GRANTS 不再显示 ALL PRIVILEGES 其全局特权输出,因为 ALL PRIVILEGES 全局级别 的含义 取决于定义的动态特权。 相反, SHOW GRANTS 明确列出每个授予的全局权限:

MySQL的> SHOW GRANTS FOR 'root'@'localhost';
+ ------------------------------------------------- -------------------- +
| root @ localhost的补助金
+ ------------------------------------------------- -------------------- +
| GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,RELOAD,|
| SHUTDOWN,PROCESS,FILE,REFERENCES,INDEX,ALTER,SHOW DATABASES,|
| 超级,创建临时表,锁定表,执行,复制|
| 奴隶,复制客户,创建视图,展示视图,创建常规,|
| ALTER ROUTINE,CREATE USER,EVENT,TRIGGER,CREATE TABLESPACE,|
| 创建角色,降低角色*。*到`root` @`localhost` WITH GRANT |
| 选项|
| 授予''''''''''''''''''''''''''''''''''''''''''''''''''''
+ ------------------------------------------------- -------------------- +

SHOW GRANTS 应相应调整 处理 输出的 应用程序

在全局级别, GRANT OPTION 如果为其中任何一个授予 ,则 应用于所有已授予的静态全局特权,但单独应用于授予的动态特权。 SHOW GRANTS 以这种方式显示全局特权:

  • 列出所有已授予的静态权限的一行(如果有),包括 WITH GRANT OPTION 适当的 权限

  • 一行列出了授予的所有授予的动态权限 GRANT OPTION ,如果有的话,包括 WITH GRANT OPTION

  • 一行列出了 GRANT OPTION 未授予的 所有已授予的动态权限 ,如果有,则没有 WITH GRANT OPTION

使用optional USING 子句, SHOW GRANTS 可以检查与用户角色关联的权限。 USING 必须 将该 子句 中指定的每个角色 授予用户。

假设用户 u1 被赋予的角色 r1 r2 ,如下所示:

CREATE ROLE'r1','r2';
GRANT SELECT ON db1。* TO'r1';
GRANT INSERT,UPDATE,DELETE ON db1。* TO'r2';
创建用户'u1'@'localhost'通过'u1pass'识别;
GRANT'r1','r2'到'u1'@'localhost';

SHOW GRANTS 没有 USING 显示授予的角色:

MySQL的> SHOW GRANTS FOR 'u1'@'localhost';
+ --------------------------------------------- +
| u1 @ localhost的补助金
+ --------------------------------------------- +
| 授予使用*。*给'u1` @`localhost` |
| GRANT`r1` @`%`,`r2` @`%`to`u1` @`localhost` |
+ --------------------------------------------- +

添加 USING 子句会导致语句还显示与子句中指定的每个角色关联的权限:

MySQL的> SHOW GRANTS FOR 'u1'@'localhost' USING 'r1';
+ --------------------------------------------- +
| u1 @ localhost的补助金
+ --------------------------------------------- +
| 授予使用*。*给'u1` @`localhost` |
| GRANT SELECT ON`db1`。* to`u1` @`localhost` |
| GRANT`r1` @`%`,`r2` @`%`to`u1` @`localhost` |
+ --------------------------------------------- +
MySQL的> SHOW GRANTS FOR 'u1'@'localhost' USING 'r2';
+ ------------------------------------------------- ------------ +
| u1 @ localhost的补助金
+ ------------------------------------------------- ------------ +
| 授予使用*。*给'u1` @`localhost` |
| GRANT INSERT,UPDATE,DELETE ON`db1`。* to`u1` @`localhost` |
| GRANT`r1` @`%`,`r2` @`%`to`u1` @`localhost` |
+ ------------------------------------------------- ------------ +
MySQL的> SHOW GRANTS FOR 'u1'@'localhost' USING 'r1', 'r2';
+ ------------------------------------------------- -------------------- +
| u1 @ localhost的补助金
+ ------------------------------------------------- -------------------- +
| 授予使用*。*给'u1` @`localhost` |
| GRANT SELECT,INSERT,UPDATE,DELETE ON`db1`。* to`u1` @`localhost` |
| GRANT`r1` @`%`,`r2` @`%`to`u1` @`localhost` |
+ ------------------------------------------------- -------------------- +
注意

授予帐户的权限始终有效,但角色不是。 帐户的活动角色可以在会话期间和会话内不同,具体取决于 activate_all_roles_on_login 系统变量 的值 ,帐户默认角色以及是否 SET ROLE 已在会话中执行。

MySQL 8.0.16及更高版本支持部分撤销全局特权,这样可以限制全局特权应用于特定模式(请参见 第6.2.12节“使用部分撤消特权限制” )。 要指示已为特定模式撤消了哪些全局模式特权, SHOW GRANTS 输出包括 REVOKE 语句:

mysql> SET PERSIST partial_revokes = ON;
mysql> CREATE USER u1;
mysql> GRANT SELECT, INSERT, DELETE ON *.* TO u1;
mysql> REVOKE SELECT, INSERT ON mysql.* FROM u1;
mysql> REVOKE DELETE ON world.* FROM u1;
mysql>SHOW GRANTS FOR u1;
+ ------------------------------------------------- -  +
| 为u1 @%|拨款
+ ------------------------------------------------- -  +
| GRANT SELECT,INSERT,DELETE ON *。* TO`u1` @`%`|
| REVOKE SELECT,INSERT ON`mysql`。* FROM`u1` @`%`|
| REVOKE DELETE ON`world`。* FROM`u1` @`%`|
+ ------------------------------------------------- -  +

SHOW GRANTS 不显示指定帐户可用但被授予其他帐户的权限。 例如,如果存在匿名帐户,则指定的帐户可能能够使用其权限,但 SHOW GRANTS 不会显示它们。

SHOW GRANTS 显示 mandatory_roles 系统变量值中 指定的必需角色 ,如下所示:

  • SHOW GRANTS without FOR 子句显示当前用户的权限,并包括必需的角色。

  • SHOW GRANTS FOR user 显示指定用户的权限,不包括必需的角色。

此行为是为了使用输出的应用程序的好处, 以确定明确授予指定用户的权限。 如果该输出包含强制角色,则很难将明确授予用户的角色与强制角色区分开来。 SHOW GRANTS FOR user

对于当前用户,应用程序可以 分别 使用 SHOW GRANTS 确定具有或不具有强制角色的权限 SHOW GRANTS FOR CURRENT_USER

13.7.6.22 SHOW INDEX语法

SHOW [EXTENDED] {INDEX | INDEXES | KEYS}
    {FROM | IN} tbl_name
    [{FROM | 在}db_name]
    [在哪里expr]

SHOW INDEX 返回表索引信息。 格式类似于 SQLStatistics ODBC 中的 调用。 此语句需要表中任何列的某些权限。

MySQL的> SHOW INDEX FROM City\G
*************************** 1。排******************** *******
        表:城市
   非独特:0
     Key_name:PRIMARY
 Seq_in_index:1
  Column_name:ID
    整理:A
  基数:4188
     Sub_part:NULL
       打包:NULL
         空值:
   Index_type:BTREE
      评论:
Index_comment:
      可见:是的
   表达式:NULL
*************************** 2.排******************** *******
        表:城市
   非独特:1
     Key_name:CountryCode
 Seq_in_index:1
  Column_name:CountryCode
    整理:A
  基数:232
     Sub_part:NULL
       打包:NULL
         空值:
   Index_type:BTREE
      评论:
Index_comment:
      可见:是的
   表达式:NULL

语法 的替代方法 这两个陈述是等价的: tbl_name FROM db_name db_name tbl_name

从mytable FROM mydb显示索引;
显示来自mydb.mytable的索引;

可选 EXTENDED 关键字使输出包含有关MySQL内部使用且用户无法访问的隐藏索引的信息。

WHERE 子句可以使用更一般的条件来选择行,如 第25.42节“扩展到SHOW语句”中所述

SHOW INDEX 返回以下字段:

  • Table

    表的名称。

  • Non_unique

    如果索引不能包含重复项,则为0;如果可以,则为1。

  • Key_name

    索引的名称。 如果索引是主键,则名称始终为 PRIMARY

  • Seq_in_index

    索引中的列序列号,以1开头。

  • Column_name

    列名称。 另请参见该 Expression 的说明

  • Collation

    列如何在索引中排序。 这可以具有值 A (升序), D (降序)或 NULL (未排序)。

  • Cardinality

    估计索引中的唯一值的数量。 要更新此号码,请运行 ANALYZE TABLE 或(对于 MyISAM 表格) myisamchk -a

    Cardinality 根据存储为整数的统计信息计算,因此即使对于小型表,该值也不一定精确。 基数越高,MySQL在进行连接时使用索引的可能性就越大。

  • Sub_part

    索引前缀。 也就是说, NULL 如果整列被索引 那么如果 列仅被部分索引, 索引字符的数量

    注意

    前缀 限制 以字节为单位。 然而,前缀 长度 为索引规范 CREATE TABLE ALTER TABLE CREATE INDEX 语句解释为非二进制字符串类型(字符数 CHAR VARCHAR TEXT )和字节数为二进制串类型( BINARY VARBINARY BLOB )。 在为使用多字节字符集的非二进制字符串列指定前缀长度时,请考虑这一点。

    有关索引前缀的其他信息,请参见 第8.3.5节“列索引” 第13.1.15节“CREATE INDEX语法”

  • Packed

    指示密钥的打包方式。 NULL 如果不是。

  • Null

    包含 YES 如果列可能包含 NULL 的值和 '' 如果不。

  • Index_type

    使用的索引方法( BTREE FULLTEXT HASH RTREE )。

  • Comment

    有关未在其自己的列中描述的索引的信息,例如 disabled 是否已禁用索引。

  • Index_comment

    COMMENT 在创建索引时为索引 提供的任何注释都带有 属性。

  • Visible

    索引是否对优化程序可见。 请参见 第8.3.12节“不可见索引”

  • Expression

    MySQL 8.0.13及更高版本支持功能关键部分(请参阅 功能键部件 ),它会影响 Column_name Expression 列:

    • 对于非功能键部分, Column_name 表示由键部分索引的列,并且 Expression NULL

    • 对于功能键部分, Column_name 列是 NULL Expression 指示关键部分的表达式。

表中还提供了有关表索引的信息 INFORMATION_SCHEMA STATISTICS 请参见 第25.26节“INFORMATION_SCHEMA STATISTICS表” 有关隐藏索引的扩展信息仅可使用 SHOW EXTENDED INDEX ; 它不能从 STATISTICS 表中 获得

您可以使用 mysqlshow -k db_name tbl_name 命令 列出表的索引

13.7.6.23 SHOW MASTER STATUS语法

显示主要状态

此语句提供有关主服务器的二进制日志文件的状态信息。 它需要 SUPER REPLICATION CLIENT 特权。

例:

MySQL的> SHOW MASTER STATUS\G
*************************** 1。排******************** *******
             文件:master-bin.000002
         位置:1307
     Binlog_Do_DB:测试
 Binlog_Ignore_DB:手动,mysql
Executed_Gtid_Set:3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5
1排(0.00秒)

使用全局事务ID时, Executed_Gtid_Set 显示已在主服务器上执行的事务的GTID集。 这与 gtid_executed 此服务器上 系统变量 的值相同,也与 此服务器 Executed_Gtid_Set 的输出中 的值相同 SHOW SLAVE STATUS

13.7.6.24显示OPEN TABLES语法

显示开放表格
    [{FROM | 在}db_name ]
    [喜欢' pattern'| 在哪里expr]

SHOW OPEN TABLES 列出 TEMPORARY 表缓存中当前打开 的非 表。 请参见 第8.4.3.1节“MySQL如何打开和关闭表” FROM 子句(如果存在)将显示的表限制为 db_name 数据库中 存在的表 LIKE 子句(如果存在)指示要匹配的表名。 WHERE 子句可以使用更一般的条件来选择行,如 第25.42节“扩展到SHOW语句”中所述

SHOW OPEN TABLES 输出有以下列:

  • Database

    包含表的数据库。

  • Table

    表名。

  • In_use

    表的锁表或锁请求的数量。 例如,如果一个客户端使用获取锁定为一个表 LOCK TABLE t1 WRITE In_use 将是1,如果其他客户端的问题 LOCK TABLE t1 WRITE ,而表保持锁定时,客户端将阻塞等待锁,但是锁定请求会导致 In_use 为2。如果计数零,表已打开但当前未使用。 声明 In_use 也增加了 HANDLER ... OPEN ,减少了 HANDLER ... CLOSE

  • Name_locked

    表名是否已锁定。 名称锁定用于执行诸如删除或重命名表之类的操作。

如果您没有表的权限,则它不会显示在输出中 SHOW OPEN TABLES

13.7.6.25 SHOW PLUGINS语法

显示插件

SHOW PLUGINS 显示有关服务器插件的信息。

SHOW PLUGINS 输出 示例

MySQL的> SHOW PLUGINS\G
*************************** 1。排******************** *******
   名称:binlog
 状态:ACTIVE
   类型:存储引擎
库:NULL
许可证:GPL
*************************** 2.排******************** *******
   名称:CSV
 状态:ACTIVE
   类型:存储引擎
库:NULL
许可证:GPL
*************************** 3。排******************** *******
   名称:记忆
 状态:ACTIVE
   类型:存储引擎
库:NULL
许可证:GPL
****************************排******************** *******
   姓名:MyISAM
 状态:ACTIVE
   类型:存储引擎
库:NULL
许可证:GPL
...

SHOW PLUGINS 输出有以下列:

  • Name

    用于在诸如 INSTALL PLUGIN 和之类的 语句中引用插件的名称 UNINSTALL PLUGIN

  • Status

    该插件的状态,一 ACTIVE INACTIVE DISABLED DELETING ,或 DELETED

  • Type

    该类型的插件,如 STORAGE ENGINE INFORMATION_SCHEMA ,或 AUTHENTICATION

  • Library

    插件共享库文件的名称。 这是用于在诸如 INSTALL PLUGIN 和之类的 语句中引用插件文件的名称 UNINSTALL PLUGIN 此文件位于 plugin_dir 系统变量 指定的目录中 如果库名是 NULL ,则插件编译在中,无法卸载 UNINSTALL PLUGIN

  • License

    插件的许可方式(例如 GPL )。

对于安装的插件 INSTALL PLUGIN Name Library 值也会在 mysql.plugin 系统表中 注册

有关构成所显示信息基础的插件数据结构的信息 SHOW PLUGINS ,请参见 第29.2节“MySQL插件API”

插件信息也可从 INFORMATION_SCHEMA .PLUGINS 表中获得。 请参见 第25.18节“INFORMATION_SCHEMA PLUGINS表”

13.7.6.26 SHOW PRIVILEGES语法

显示特权

SHOW PRIVILEGES 显示MySQL服务器支持的系统权限列表。 显示的权限包括所有静态权限和所有当前注册的动态权限。

MySQL的> SHOW PRIVILEGES\G
*************************** 1。排******************** *******
特权:改变
  上下文:表
  评论:改变表格
*************************** 2.排******************** *******
特权:改变常规
  背景:功能,程序
  注释:更改或删除存储的函数/过程
*************************** 3。排******************** *******
特权:创造
  上下文:数据库,表,索引
  注释:创建新数据库和表
****************************排******************** *******
特权:创建例程
  上下文:数据库
  注释:使用CREATE FUNCTION / PROCEDURE
****************************排******************** *******
权限:创建临时表
  上下文:数据库
  注释:使用CREATE TEMPORARY TABLE
...

SHOW GRANTS 声明 显示属于特定用户的权限 有关 更多信息 请参见 第13.7.6.21节“SHOW GRANTS语法”

13.7.6.27 SHOW PROCEDURE CODE语法

显示程序代码 proc_name

此语句是MySQL扩展,仅适用于已使用调试支持构建的服务器。 它显示命名存储过程的内部实现的表示。 类似的语句 SHOW FUNCTION CODE 显示有关存储函数的信息(请参见 第13.7.6.19节“显示函数代码语法” )。

要使用任一语句,您必须具有全局 SELECT 特权。

如果命名例程可用,则每个语句都会生成结果集。 结果集中的每一行对应 于例程中的 一个 指令 第一列是 Pos 从0开始的序数。第二列是 Instruction 包含SQL语句(通常从原始源更改)或者只对存储例程处理程序有意义的指令。

mysql> DELIMITER //
mysql> CREATE PROCEDURE p1 ()
    - > BEGIN
    - >    DECLARE fanta INT DEFAULT 55;
    - >    DROP TABLE t2;
    - >    LOOP
    - >      INSERT INTO t3 VALUES (fanta);
    - >      END LOOP;
    - >   END//
查询正常,0行受影响(0.00秒)

MySQL的> SHOW PROCEDURE CODE p1//
+ ----- + ---------------------------------------- +
| Pos | 说明|
+ ----- + ---------------------------------------- +
| 0 | 设置fanta @ 0 55 |
| 1 | stmt 9“DROP TABLE t2”|
| 2 | stmt 5“INSERT INTO t3 VALUES(fanta)”|
| 3 | 跳2 |
+ ----- + ---------------------------------------- +
4行(0.00秒)

在此示例中,不可执行 BEGIN END 语句已消失,对于 语句,仅显示可执行部分(分配默认值的部分)。 对于从源代码中获取的每个语句,都有一个代码字 后跟一个类型(9表示 ,5表示 ,依此类推)。 最后一行包含一条指令 ,意思是 DECLARE variable_name stmt DROP INSERT jump 2 GOTO instruction #2

13.7.6.28 SHOW PROCEDURE STATUS语法

显示程序状态
    [喜欢' pattern'| 在哪里expr]

该语句是MySQL扩展。 它返回存储过程的特征,例如数据库,名称,类型,创建者,创建和修改日期以及字符集信息。 类似的语句 SHOW FUNCTION STATUS 显示有关存储函数的信息(参见 第13.7.6.20节“显示函数状态语法” )。

LIKE 子句(如果存在)指示要匹配的过程或函数名称。 WHERE 子句可以使用更一般的条件来选择行,如 第25.42节“扩展到SHOW语句”中所述

MySQL的> SHOW PROCEDURE STATUS LIKE 'sp1'\G
*************************** 1。排******************** *******
                  Db:测试
                名称:sp1
                类型:程序
             定义者:testuser @ localhost
            修改时间:2018-08-08 13:54:11
             创建时间:2018-08-08 13:54:11
       Security_type:DEFINER
             评论:
character_set_client:utf8mb4
collat​​ion_connection:utf8mb4_0900_ai_ci
  数据库整理:utf8mb4_0900_ai_ci

character_set_client character_set_client 创建例程时系统变量 的会话值 collation_connection collation_connection 创建例程时系统变量 的会话值 Database Collation 是与例程关联的数据库的排序规则。

存储的例程信息也可以从 INFORMATION_SCHEMA PARAMETERS ROUTINES 表中获得。 请参见 第25.16节“INFORMATION_SCHEMA参数表” 第25.23节“INFORMATION_SCHEMA ROUTINES表”

13.7.6.29 SHOW PROCESSLIST语法

显示[FULL] PROCESSLIST

SHOW PROCESSLIST 显示正在运行的线程。 如果您有 PROCESS 权限,则可以查看所有主题。 否则,您只能看到自己的线程(即与您正在使用的MySQL帐户关联的线程)。 如果不使用 FULL 关键字,则只在 Info 字段 中显示每个语句的前100个字符

SHOW PROCESSLIST 如果您收到 太多连接 错误消息并想知道发生了什么, 语句非常有用 MySQL保留一个额外的连接以供具有 CONNECTION_ADMIN SUPER 特权 的帐户使用 ,以确保管理员应始终能够连接并检查系统(假设您没有向所有用户提供此特权)。

可以使用 KILL 语句 终止线程 请参见 第13.7.7.4节“KILL语法”

SHOW PROCESSLIST 输出 示例

mysql> SHOW FULL PROCESSLIST \ G.
*************************** 1。排******************** *******
Id:1
用户:系统用户
主办:
db:NULL
命令:连接
时间:1030455
州:等待主人发送事件
信息:NULL
*************************** 2.排******************** *******
Id:2
用户:系统用户
主办:
db:NULL
命令:连接
时间:1004
状态:已读取所有中继日志; 等待奴隶
       I / O线程更新它
信息:NULL
*************************** 3。排******************** *******
Id:3112
用户:replikator
主持人:artemis:2204
db:NULL
命令:Binlog转储
时间:2144
状态:已将所有binlog发送给奴隶; 等待binlog更新
信息:NULL
****************************排******************** *******
Id:3113
用户:replikator
主持人:iconnect2:45781
db:NULL
命令:Binlog转储
时间:2086年
状态:已将所有binlog发送给奴隶; 等待binlog更新
信息:NULL
****************************排******************** *******
Id:3123
网友:stefan
主持人:localhost
db:apollon
命令:查询
时间:0
状态:NULL
信息:显示完整的流程列表
5行(0.00秒)

SHOW PROCESSLIST 输出有以下列:

  • Id

    连接标识符。 这是同一类型的在所显示的值 ID 的列 INFORMATION_SCHEMA PROCESSLIST 表,该 PROCESSLIST_ID 性能图式的列 threads 表,并且通过返回的 CONNECTION_ID() 功能。

  • User

    发出声明的MySQL用户。 值是 system user 指服务器在内部处理任务而生成的非客户端线程。 这可能是复制从属或延迟行处理程序上使用的I / O或SQL线程。 对于 system user Host 列中 未指定主机 unauthenticated user 指的是已与客户端连接关联但尚未对客户端用户进行身份验证的线程。 event_scheduler 指监视预定事件的线程(请参见 第24.4节“使用事件调度程序” )。

    注意

    User 的值 system user 是从不同的 SYSTEM_USER 特权。 前者指定内部线程。 后者区分系统用户和常规用户帐户类别(请参见 第6.2.11节“帐户类别” )。

  • Host

    发出语句的客户端的主机名(除了 system user 没有主机 的客户端 )。 TCP / IP连接的主机名以 格式 报告, 以便更容易确定哪个客户端正在执行哪些操作。 host_name:client_port

  • db

    默认数据库(如果选择了一个); 否则 NULL

  • Command

    线程正在执行的命令类型。 有关线程命令的说明,请参见 第8.14节“检查线程信息” 此列的值对应于 客户端/服务器协议和 状态变量 命令 请参见 第5.1.10节“服务器状态变量” COM_xxx Com_xxx

  • Time

    线程处于当前状态的时间(以秒为单位)。 对于从属SQL线程,该值是最后一个复制事件的时间戳与从属机器的实时之间的秒数。 请参见 第17.2.2节“复制实现细节”

  • State

    指示线程正在执行的操作,事件或状态。 有关 State 值的 说明,请 参见 第8.14节“检查线程信息”

    大多数州对应于非常快速的操作。 如果一个线程在给定状态下停留很多秒,则可能存在需要调查的问题。

    对于 SHOW PROCESSLIST 声明中的价值 State NULL

  • Info

    线程正在执行的语句,或者 NULL 它是否正在执行任何语句。 语句可能是发送到服务器的语句,如果语句执行其他语句,则可能是最内层语句。 例如,如果 CALL 语句执行正在执行语句的存储过程,则 SELECT Info 值显示该 SELECT 语句。

还可以从 mysqladmin processlist 命令, INFORMATION_SCHEMA PROCESSLIST 表和Performance Schema threads 表中 获取进程信息 (请参见 第4.5.2节“ mysqladmin - 管理MySQL服务器的客户端” 第25.19节“INFORMATION_SCHEMA PROCESSLIST表” 第26.12节)。 .17.5,“线程表” )。 INFORMATION_SCHEMA PROCESSLIST 表和 SHOW PROCESSLIST 语句相比,由于它们需要互斥锁而导致性能损失,因此访问 threads 不需要互斥锁,并且对服务器性能的影响最小。 threads 表还显示了有关后台线程的信息, PROCESSLIST 表中 SHOW PROCESSLIST 没有。 这意味着 threads 可以用来监视其他线程信息源不能的活动。

13.7.6.30 SHOW PROFILE语法

显示简介[ type[,type] ...]
    [FOR QUERY n]
    [限制row_count[偏移offset]]

type:{
    所有
  | BLOCK IO
  | 上下文切换
  | 中央处理器
  | IPC
  | 记忆
  | 页面故障
  | 资源
  | SWAPS
}

SHOW PROFILE SHOW PROFILES 报表显示剖析,表示当前会话过程中执行的语句资源使用信息。

注意

SHOW PROFILE SHOW PROFILES 语句被取消,并将在未来的MySQL版本中删除。 请改用 Performance Schema ; 请参见 第26.19.1节“使用性能模式查询分析”

要控制性能分析,请使用 profiling 会话变量,其默认值为0( OFF )。 通过设置 profiling 为1或 启用分析 ON

MySQL的> SET profiling = 1;

SHOW PROFILES 显示发送到服务器的最新语句的列表。 列表的大小由 profiling_history_size 会话变量 控制,该 变量的默认值为15.最大值为100.将值设置为0具有禁用分析的实际效果。

除了 SHOW PROFILE 之外 所有语句都被分析 SHOW PROFILES ,因此您不会在配置文件列表中找到这些语句。 格式错误的陈述是分析的。 例如, SHOW PROFILING 是一个非法语句,如果您尝试执行它会发生语法错误,但它将显示在分析列表中。

SHOW PROFILE 显示有关单个语句的详细信息。 如果没有该 子句,则输出与最近执行的语句有关。 如果 包含,则 显示语句信息 对应于 显示 FOR QUERY n FOR QUERY n SHOW PROFILE n n Query_ID SHOW PROFILES

可以给出 子句以将输出限制为 行。 如果 给出, 可以添加以将输出 开始 到完整的行集。 LIMIT row_count row_count LIMIT OFFSET offset offset

默认情况下, SHOW PROFILE 显示 Status Duration 列。 这些 Status 值与 State 显示 值类似 SHOW PROCESSLIST ,尽管某些状态值的两个语句的解释可能存在一些细微差别(请参见 第8.14节“检查线程信息” )。

type 可以指定 可选 值以显示特定的其他类型的信息:

  • ALL 显示所有信息

  • BLOCK IO 显示块输入和输出操作的计数

  • CONTEXT SWITCHES 显示自愿和非自愿上下文切换的计数

  • CPU 显示用户和系统CPU使用时间

  • IPC 显示发送和接收的消息的计数

  • MEMORY 目前尚未实施

  • PAGE FAULTS 显示主要和次要页面错误的计数

  • SOURCE 显示源代码中的函数名称,以及函数发生的文件的名称和行号

  • SWAPS 显示交换计数

每个会话启用性能分析。 会话结束时,其分析信息将丢失。

MySQL的> SELECT @@profiling;
+ ------------- +
| @@ profiling |
+ ------------- +
| 0 |
+ ------------- +
1排(0.00秒)

MySQL的> SET profiling = 1;
查询正常,0行受影响(0.00秒)

MySQL的> DROP TABLE IF EXISTS t1;
查询正常,0行受影响,1警告(0.00秒)

MySQL的> CREATE TABLE T1 (id INT);
查询OK,0行受影响(0.01秒)

MySQL的> SHOW PROFILES;
+ ---------- + ---------- + -------------------------- +
| Query_ID | 持续时间| 查询|
+ ---------- + ---------- + -------------------------- +
| 0 | 0.000088 | SET PROFILING = 1 |
| 1 | 0.000136 | DROP TABLE IF EXISTS t1 |
| 2 | 0.011947 | CREATE TABLE t1(id INT)|
+ ---------- + ---------- + -------------------------- +
3组(0.00秒)

MySQL的> SHOW PROFILE;
+ ---------------------- + ---------- +
| 状态| 持续时间|
+ ---------------------- + ---------- +
| 检查权限| 0.000040 |
| 创建表| 0.000056 |
| 创建后| 0.011363 |
| 查询结束| 0.000375 |
| 释放物品| 0.000089 |
| 记录慢查询| 0.000019 |
| 清理| 0.000005 |
+ ---------------------- + ---------- +
7行(0.00秒)

MySQL的> SHOW PROFILE FOR QUERY 1;
+ -------------------- + ---------- +
| 状态| 持续时间|
+ -------------------- + ---------- +
| 查询结束| 0.000107 |
| 释放物品| 0.000008 |
| 记录慢查询| 0.000015 |
| 清理| 0.000006 |
+ -------------------- + ---------- +
4行(0.00秒)

MySQL的> SHOW PROFILE CPU FOR QUERY 2;
+ ---------------------- + ---------- + ---------- + ---- -------- +
| 状态| 持续时间| CPU_user | CPU_system |
+ ---------------------- + ---------- + ---------- + ---- -------- +
| 检查权限| 0.000040 | 0.000038 | 0.000002 |
| 创建表| 0.000056 | 0.000028 | 0.000028 |
| 创建后| 0.011363 | 0.000217 | 0.001571 |
| 查询结束| 0.000375 | 0.000013 | 0.000028 |
| 释放物品| 0.000089 | 0.000010 | 0.000014 |
| 记录慢查询| 0.000019 | 0.000009 | 0.000010 |
| 清理| 0.000005 | 0.000003 | 0.000002 |
+ ---------------------- + ---------- + ---------- + ---- -------- +
7行(0.00秒)
注意

分析仅在某些体系结构上具有部分功能。 对于依赖于 getrusage() 系统调用的 值, NULL 将在不支持该调用的Windows等系统上返回。 此外,分析是每个进程而不是每个线程。 这意味着除了您自己的服务器之外的服务器上的线程上的活动可能会影响您看到的计时信息。

INFORMATION_SCHEMA PROFILING 表中 还提供了性能分析信息 请参见 第25.20节“INFORMATION_SCHEMA PROFILING表” 例如,以下查询是等效的:

显示查询2;

选择状态,格式化(持续时间,6)作为持续时间
来自INFORMATION_SCHEMA.PROFILING
WHERE QUERY_ID = 2 ORDER BY SEQ;

13.7.6.31 SHOW PROFILES语法

显示配置文件

SHOW PROFILES 语句与 SHOW PROFILE 显示的分析信息 一起 显示了在当前会话过程中执行的语句的资源使用情况。 有关更多信息,请参见 第13.7.6.30节“显示配置文件语法”

注意

SHOW PROFILE SHOW PROFILES 语句被取消,并将在未来的MySQL版本中删除。 请改用 Performance Schema ; 请参见 第26.19.1节“使用性能模式查询分析”

13.7.6.32显示RELAYLOG EVENTS语法

显示RELAYLOG活动
    [IN' log_name']
    [从 pos ]
    [限制[ offset,] row_count]
    [ channel_option]

channel_option
    FOR CHANNEL channel

显示复制从站的中继日志中的事件。 如果未指定 ,则显示第一个中继日志。 该声明对主人没有影响。 需要 特权。 'log_name' SHOW RELAYLOG EVENTS REPLICATION SLAVE

LIMIT 子句的语法与 SELECT 语句 相同 请参见 第13.2.10节“SELECT语法”

注意

发出 SHOW RELAYLOG EVENTS no with no LIMIT 子句可能会启动耗费时间和资源的过程,因为服务器会向中心返回中继日志的完整内容(包括修改从站接收的数据的所有语句)。

使用optional 子句可以命名该语句适用的复制通道。 提供 子句将语句应用于特定复制通道。 如果未命名通道且不存在额外通道,则该语句将应用于默认通道。 FOR CHANNEL channel FOR CHANNEL channel

使用多个复制通道时,如果 SHOW RELAYLOG EVENTS 语句没有使用 子句 定义的 通道,则会 生成错误。 有关 更多信息 请参见 第17.2.3节“复制通道” FOR CHANNEL channel

SHOW RELAYLOG EVENTS 显示中继日志中每个事件的以下字段:

  • Log_name

    要列出的文件的名称。

  • Pos

    事件发生的位置。

  • Event_type

    描述事件类型的标识符。

  • Server_id

    发生事件的服务器的服务器ID。

  • End_log_pos

    End_log_pos 此事件在主人的二进制日志。

  • Info

    有关事件类型的更多详细信息。 此信息的格式取决于事件类型。

注意

与设置用户和系统变量有关的一些事件不包括在输出中 SHOW RELAYLOG EVENTS 要完全了解中继日志中的事件,请使用 mysqlbinlog

13.7.6.33 SHOW SLAVE HOSTS语法

SHOW SLAVE HOSTS

显示当前向主服务器注册的复制从服务器列表。 SHOW SLAVE HOSTS 需要 REPLICATION SLAVE 特权。

SHOW SLAVE HOSTS 应该在充当复制主服务器的服务器上执行。 该语句显示有关已连接或已连接为复制从属服务器的信息,结果的每一行对应一个从属服务器,如下所示:

mysql> SHOW SLAVE HOSTS;
+ ------------ + ----------- ------ + + ----------- + ----- --------------------------------- +
| Server_id | 主持人| 港口| Master_id | Slave_UUID |
+ ------------ + ----------- ------ + + ----------- + ----- --------------------------------- +
| 192168010 | iconnect2 | 3306 | 192168011 | 14cb6624-7f93-11e0-b2c0-c80aa9429562 |
| 1921680101 | 雅典娜| 3306 | 192168011 | 07af4990-f41f-11df-a566-7ac56fdaf645 |
+ ------------ + ----------- ------ + + ----------- + ----- --------------------------------- +
  • Server_id :从服务器的唯一服务器ID,在从服务器的选项文件中配置,或在命令行中配置 --server-id=value

  • Host :带有 --report-host 选项 的从站上指定的从服务器的主机名 这可能与操作系统中配置的计算机名称不同。

  • User :从服务器用户名as,在带有 --report-user 选项 的从站上指定 仅当使用该 --show-slave-auth-info 选项 启动主服务器时,语句输出才包含此列

  • Password :从服务器密码as,在带有 --report-password 选项 的从站上指定 仅当使用该 --show-slave-auth-info 选项 启动主服务器时,语句输出才包含此列

  • Port :从服务器正在侦听的主服务器上的端口,如带有 --report-port 选项 的从服务器上指定的那样

    此列中的零表示 --report-port 未设置 从端口( )。

  • Master_id :从服务器正在复制的主服务器的唯一服务器ID。 这是执行的服务器的服务器ID SHOW SLAVE HOSTS ,因此为结果中的每一行列出了相同的值。

  • Slave_UUID :此从站的全局唯一ID,在从站上生成并在从站 auto.cnf 文件中找到。

13.7.6.34 SHOW SLAVE STATUS语法

SHOW SLAVE STATUS [FOR CHANNEL channel]

此语句提供有关从属线程的基本参数的状态信息。 它需要 SUPER REPLICATION CLIENT 特权。

SHOW SLAVE STATUS 是非阻塞的。 与其同时运行时 STOP SLAVE SHOW SLAVE STATUS 返回时无需等待 STOP SLAVE 完成关闭从属SQL线程或从属I / O线程(或两者)。 这允许在监视和其他应用程序中使用,其中立即响应 SHOW SLAVE STATUS 比确保它返回最新数据更重要。

如果使用 mysql 客户端 发出此语句 ,则可以使用 \G 语句终止符而不是分号来获得更易读的垂直布局:

MySQL的> SHOW SLAVE STATUS\G
*************************** 1。排******************** *******
               Slave_IO_State:等待主节点发送事件
                  Master_Host:localhost
                  Master_User:repl
                  Master_Port:13000
                Connect_Retry:60
              Master_Log_File:master-bin.000002
          Read_Master_Log_Pos:1307
               Relay_Log_File:slave-relay-bin.000003
                Relay_Log_Pos:1508
        Relay_Master_Log_File:master-bin.000002
             Slave_IO_Running:是的
            Slave_SQL_Running:是的
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno:0
                   Last_Error:
                 Skip_Counter:0
          Exec_Master_Log_Pos:1307
              Relay_Log_Space:1858
              Until_Condition:无
               Until_Log_File:
                Until_Log_Pos:0
           Master_SSL_Allowed:没有
           Master_SSL_CA_File:
           Master_SSL_CA_Path:
              Master_SSL_Cert:
            Master_SSL_Cipher:
               Master_SSL_Key:
        Seconds_Behind_Master:0
Master_SSL_Verify_Server_Cert:没有
                Last_IO_Errno:0
                Last_IO_Error:
               Last_SQL_Errno:0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id:1
                  Master_UUID:3e11fa47-71ca-11e1-9e33-c80aa9429562
             Master_Info_File:/var/mysqld.2/data/master.info
                    SQL_Delay:0
          SQL_Remaining_Delay:NULL
      Slave_SQL_Running_State:从中继日志中读取事件
           Master_Retry_Count:10
                  Master_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set:3e11fa47-71ca-11e1-9e33-c80aa9429562:1-5
            Executed_Gtid_Set:3e11fa47-71ca-11e1-9e33-c80aa9429562:1-5
                Auto_Position:1
         Replicate_Rewrite_DB:
                 CHANNEL_NAME:
           Master_TLS_Version:TLSv1.2
       Master_public_key_path:public_key.pem
        Get_master_public_key:0

性能模式提供了公开复制信息的表。 这与 SHOW SLAVE STATUS 声明中 提供的信息类似 ,但以表格形式表示。 有关详细信息,请参见 第26.12.11节“性能模式复制表”

以下列表描述了返回的字段 SHOW SLAVE STATUS 有关解释其含义的其他信息,请参见 第17.1.7.1节“检查复制状态”

  • Slave_IO_State

    从属I / O线程 State SHOW PROCESSLIST 输出 字段的 副本 这告诉您线程正在做什么:尝试连接到主服务器,等待主服务器的事件,重新连接到主服务器,等等。 有关可能状态的列表,请参见 第8.14.4节“复制从站I / O线程状态”

  • Master_Host

    从属设备连接的主控主机。

  • Master_User

    用于连接到主服务器的帐户的用户名。

  • Master_Port

    用于连接主服务器的端口。

  • Connect_Retry

    连接重试之间的秒数(默认为60)。 这可以使用 CHANGE MASTER TO 语句 设置

  • Master_Log_File

    I / O线程当前正在读取的主二进制日志文件的名称。

  • Read_Master_Log_Pos

    I / O线程读取的当前主二进制日志文件中的位置。

  • Relay_Log_File

    SQL线程当前正在读取和执行的中继日志文件的名称。

  • Relay_Log_Pos

    当前中继日志文件中SQL线程已读取和执行的位置。

  • Relay_Master_Log_File

    包含SQL线程执行的最新事件的主二进制日志文件的名称。

  • Slave_IO_Running

    I / O线程是否已启动并已成功连接到主站。 在内部,此线程的状态由以下三个值之一表示:

    • MYSQL_SLAVE_NOT_RUN。  从I / O线程未运行。 对于这种状态, Slave_IO_Running No

    • MYSQL_SLAVE_RUN_NOT_CONNECT。  从I / O线程正在运行,但未连接到复制主机。 对于这种状态, Slave_IO_Running Connecting

    • MYSQL_SLAVE_RUN_CONNECT。  从I / O线程正在运行,并连接到复制主机。 对于这种状态, Slave_IO_Running Yes

    所述的值 Slave_running 系统状态变量对应于该值。

  • Slave_SQL_Running

    SQL线程是否已启动。

  • Replicate_Do_DB Replicate_Ignore_DB

    使用 --replicate-do-db --replicate-ignore-db 选项或 CHANGE REPLICATION FILTER 语句 指定的任何数据库的名称 如果使用该 FOR CHANNEL 子句,则会显示特定于通道的复制过滤器。 否则,将显示每个复制通道的复制筛选器。

  • Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table

    与被指定的任何表的名称 --replicate-do-table --replicate-ignore-table --replicate-wild-do-table ,和 --replicate-wild-ignore-table 选项,或 CHANGE REPLICATION FILTER 声明。 如果使用该 FOR CHANNEL 子句,则会显示特定于通道的复制过滤器。 否则,将显示每个复制通道的复制筛选器。

  • Last_Errno Last_Error

    这些列是 Last_SQL_Errno 和的 别名 Last_SQL_Error

    发出 RESET MASTER RESET SLAVE 重置这些列中显示的值。

    注意

    当从属SQL线程收到错误时,它首先报告错误,然后停止SQL线程。 这意味着有一个小的时间窗口,在此期间 即使 仍然显示 SHOW SLAVE STATUS 显示非零值 Last_SQL_Errno Slave_SQL_Running Yes

  • Skip_Counter

    sql_slave_skip_counter 系统变量 的当前值 请参见 第13.4.2.5节“SE​​T GLOBAL sql_slave_skip_counter语法”

  • Exec_Master_Log_Pos

    SQL线程已读取并执行的当前主二进制日志文件中的位置,标记要处理的下一个事务或事件的开始。 从现有从站启动新从站时, 可以将此值与 CHANGE MASTER TO 语句 MASTER_LOG_POS 选项 一起使用 ,以便新从站从此点读取。 通过给出的坐标( Relay_Master_Log_File Exec_Master_Log_Pos 在主服务器的二进制日志)对应于给出的坐标( Relay_Log_File Relay_Log_Pos 在中继日志)。

    来自中继日志的事务序列中已执行的不一致可导致该值为 低水位线 换句话说,保证在该头寸之前出现的交易已经提交,但该头寸之后的交易可能已经提交或未提交。 如果需要纠正这些差距,请使用 START SLAVE UNTIL SQL_AFTER_MTS_GAPS 有关 更多信息 请参见 第17.4.1.33节“复制和事务不一致”

  • Relay_Log_Space

    所有现有中继日志文件的总组合大小。

  • Until_Condition Until_Log_File Until_Log_Pos

    语句 UNTIL 子句中 指定的值 START SLAVE

    Until_Condition 有这些价值观:

    • None 如果没有 UNTIL 指定条款

    • Master 如果从机正在读取,直到主机二进制日志中的给定位置

    • Relay 如果从站正在读取,直到其中继日志中的给定位置

    • SQL_BEFORE_GTIDS 如果从属SQL线程正在处理事务,直到它到达其中列出GTID的第一个事务 gtid_set

    • SQL_AFTER_GTIDS 如果从属线程正在处理所有事务,直到两个线程都处理了最后一个事务 gtid_set

    • SQL_AFTER_MTS_GAPS 如果多线程从属的SQL线程正在运行,直到在中继日志中找不到更多间隙。

    Until_Log_File Until_Log_Pos 指明用于定义SQL线程停止执行的坐标的日志文件名称和位置。

    有关 UNTIL 子句的 更多信息 ,请参见 第13.4.2.6节“START SLAVE语法”

  • Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_CRL_File Master_SSL_CRL_Path Master_SSL_Key Master_SSL_Verify_Server_Cert

    这些字段显示从站用于连接到主站的SSL参数(如果有)。

    Master_SSL_Allowed 有这些价值观:

    • Yes 如果允许与主服务器建立SSL连接

    • No 如果不允许与主服务器建立SSL连接

    • Ignored 如果允许SSL连接但从服务器未启用SSL支持

    其他SSL相关的字段的值对应的值 MASTER_SSL_CA MASTER_SSL_CAPATH MASTER_SSL_CERT MASTER_SSL_CIPHER MASTER_SSL_CRL MASTER_SSL_CRLPATH MASTER_SSL_KEY ,和 MASTER_SSL_VERIFY_SERVER_CERT 选项的 CHANGE MASTER TO 说法。 请参见 第13.4.2.1节“更改主语法”

  • Seconds_Behind_Master

    该字段表示 奴隶的 迟到

    • 当从站正在主动处理更新时,此字段显示从站上当前时间戳与主站上当前正在处理的事件上记录的原始时间戳之间的差异。

    • 当从站上当前没有处理任何事件时,该值为0。

    本质上,该字段测量从属SQL线程和从属I / O线程之间的时间差(秒)。 如果主站和从站之间的网络连接速度很快,则从站I / O线程非常接近主站,因此该字段很好地近似了从站SQL线程与主站的比较。 如果网络很慢,这 不是 一个很好的近似; 从属SQL线程可能经常遇到慢速读取从属I / O线程,因此 Seconds_Behind_Master 即使I / O线程与主节点相比较晚,也经常显示值0。 换句话说, 此列仅适用于快速网络

    即使主机和从机没有相同的时钟时间,这个时间差计算仍然有效,前提是从机I / O线程启动时计算的差值从那时起保持不变。 任何更改(包括NTP更新)都可能导致时钟偏差,从而导致计算 Seconds_Behind_Master 可靠性降低。

    在MySQL 8.0中, NULL 如果从属SQL线程未运行,或者SQL线程已消耗所有中继日志且从属I / O线程未运行 ,则此字段为 (未定义或未知)。 (在旧版本的MySQL中,此字段是 NULL 从属SQL线程或从属I / O线程未运行或未连接到主服务器。)如果I / O线程正在运行但是中继日志已用完, Seconds_Behind_Master 则是设为0。

    Seconds_Behind_Master 基于存储在事件中的时间戳,这些时间戳通过复制保留。 这意味着如果主M1本身是M0的从属,则来自M1的二进制日志的任何来自M0的二进制日志的事件都具有该事件的M0时间戳。 这使MySQL能够 TIMESTAMP 成功 复制 然而,问题 Seconds_Behind_Master 是如果M1也从客户端接收直接更新,则该 Seconds_Behind_Master 值随机波动,因为有时来自M1的最后一个事件源自M0,有时是M1上的直接更新的结果。

    使用多线程从属时,应记住此值基于 Exec_Master_Log_Pos ,因此可能无法反映最近提交的事务的位置。

  • Last_IO_Errno Last_IO_Error

    导致I / O线程停止的最新错误的错误号和错误消息。 错误号为0,空字符串的消息表示 没有错误。 如果该 Last_IO_Error 值不为空,则错误值也会出现在从站的错误日志中。

    I / O错误信息包括显示最近发生的I / O线程错误的时间戳。 此时间戳使用格式 YYMMDD hh:mm:ss ,并显示在 Last_IO_Error_Timestamp 列中。

    发出 RESET MASTER RESET SLAVE 重置这些列中显示的值。

  • Last_SQL_Errno Last_SQL_Error

    导致SQL线程停止的最新错误的错误号和错误消息。 错误号为0,空字符串的消息表示 没有错误。 如果该 Last_SQL_Error 值不为空,则错误值也会出现在从站的错误日志中。

    如果从属是多线程的,则SQL线程是工作线程的协调器。 在这种情况下,该 Last_SQL_Error 字段显示 Last_Error_Message Performance Mapma replication_applier_status_by_coordinator 表中 显示的内容。 修改字段值以表明其他工作线程中可能存在更多故障,这些故障可以在 replication_applier_status_by_worker 显示每个工作线程状态 表中 看到 如果该表不可用,则可以使用从属错误日志。 replication_applier_status_by_worker 还应使用 日志或 表来了解有关 SHOW SLAVE STATUS 协调器表所 显示的故障的更多信息

    SQL错误信息包括显示最近发生SQL线程错误的时间戳。 此时间戳使用格式 YYMMDD hh:mm:ss ,并显示在 Last_SQL_Error_Timestamp 列中。

    发出 RESET MASTER RESET SLAVE 重置这些列中显示的值。

    在MySQL 8.0中, Last_SQL_Errno Last_SQL_Error 列中 显示的所有错误代码和消息都 对应于 第B.3.1节“服务器错误消息参考”中 列出的错误值 在以前的版本中并非总是如此。 (Bug#11760365,Bug#52768)

  • Replicate_Ignore_Server_Ids

    使用 语句 IGNORE_SERVER_IDS 选项 指定的任何服务器标识 CHANGE MASTER TO ,以便从属服务器忽略来自这些服务器的事件。 当删除其中一个服务器时,此选项用于循环或其他多主复制设置。 如果以这种方式设置了任何服务器ID,则会显示一个或多个数字的逗号分隔列表。 如果未设置服务器ID,则该字段为空。

    注意

    表中 Ignored_server_ids slave_master_info 还显示要忽略的服务器ID,但作为以空格分隔的列表,前面是要忽略的服务器ID总数。 例如,如果发出 CHANGE MASTER TO 包含该 IGNORE_SERVER_IDS = (2,6,9) 选项 语句 以告知从属服务器忽略具有服务器ID 2,6或9的主服务器,则该信息如下所示:

    	Replicate_Ignore_Server_Ids:2,6,9
    
    	Ignored_server_ids:3,2,6,9
    

    Replicate_Ignore_Server_Ids 过滤由I / O线程执行,而不是由SQL线程执行,这意味着过滤掉的事件不会写入中继日志。 这与服务器选项所采用的过滤操作不同 --replicate-do-table ,后者适用于SQL线程。

    注意

    从MySQL 8.0.3开始,如果 SET GTID_MODE=ON 在任何通道设置了现有服务器ID时 发出, 则会发出 弃用警告 IGNORE_SERVER_IDS 在启动基于GTID的复制之前,请使用 SHOW_SLAVE_STATUS 检查并清除所涉及的服务器上所有被忽略的服务器ID列表。 您可以通过发出 CHANGE MASTER TO 包含 IGNORE_SERVER_IDS 带有空列表 选项 语句 来清除 列表。

  • Master_Server_Id

    server_id 来自主人 价值。

  • Master_UUID

    server_uuid 来自主人 价值。

  • Master_Info_File

    master.info 如果文件而不是表用于从属主信息存储库,则文件 的位置

  • SQL_Delay

    从站必须滞后主站的秒数。

  • SQL_Remaining_Delay

    如果 Slave_SQL_Running_State Waiting until MASTER_DELAY seconds after master executed event ,则此字段包含的剩余延迟秒数。 在其他时候,这个领域是 NULL

  • Slave_SQL_Running_State

    SQL线程的状态(类似于 Slave_IO_State )。 该值与 State 显示的SQL线程 的值相同 SHOW PROCESSLIST 第8.14.5节“复制从属SQL线程状态” 提供了可能状态的列表

  • Master_Retry_Count

    在连接丢失的情况下,从站可以尝试重新连接到主站的次数。 可以使用 语句(首选)或旧 服务器选项(仍然支持向后兼容性) MASTER_RETRY_COUNT 选项 来设置此值 CHANGE MASTER TO --master-retry-count

  • Master_Bind

    从属绑定的网络接口(如果有)。 这是使用 语句 MASTER_BIND 选项设置的 CHANGE MASTER TO

  • Last_IO_Error_Timestamp

    YYMMDD hh:mm:ss 格式 的时间戳 ,显示最近的I / O错误发生的时间。

  • Last_SQL_Error_Timestamp

    YYMMDD hh:mm:ss 格式化 的时间戳 ,显示最近发生的SQL错误。

  • Retrieved_Gtid_Set

    与此从站接收的所有事务对应的全局事务ID集。 如果未使用GTID,则清空。 有关 更多信息, 请参阅 GTID集

    这是中继日志中存在或已存在的所有GTID的集合。 Gtid_log_event 收到后 立即添加每个GTID 这可能导致部分传输的事务将其GTID包含在集合中。

    当所有中继日志由于执行 RESET SLAVE CHANGE MASTER TO 由于 --relay-log-recovery 选项 的影响而 丢失时 ,该组将被清除。 何时 relay_log_purge = 1 ,始终保留最新的中继日志,并且不清除该组。

  • Executed_Gtid_Set

    在二进制日志中写入的全局事务ID集。 这与 gtid_executed 此服务器上 的全局 系统变量的值以及此服务器 Executed_Gtid_Set 的输出中 的值相同 SHOW MASTER STATUS 如果未使用GTID,则清空。 有关 更多信息, 请参阅 GTID集

  • Auto_Position

    1如果正在使用自动定位; 否则为0。

  • Replicate_Rewrite_DB

    Replicate_Rewrite_DB 值显示指定的任何复制筛选规则。 例如,如果设置了以下复制过滤规则:

    CHANGE REPLICATION FILTER REPLICATE_REWRITE_DB =((db1,db2),(db3,db4));

    Replicate_Rewrite_DB 值显示:

    Replicate_Rewrite_DB:(db1,db2),(db3,db4)

    有关更多信息,请参见 第13.4.2.2节“更改复制过滤器语法”

  • Channel_name

    正在显示的复制通道。 始终存在默认复制通道,可以添加更多复制通道。 有关 更多信息 请参见 第17.2.3节“复制通道”

  • Master_TLS_Version

    主服务器上使用的TLS版本。 有关TLS版本信息,请参见 第6.3.6节“加密连接协议和密码”

  • Master_public_key_path

    包含主服务器所需的公钥的从属端副本的文件的路径名,用于基于RSA密钥对的密码交换。 该文件必须采用PEM格式。 此列适用于使用 sha256_password caching_sha2_password 身份验证插件进行 身份验证的从属 服务器。

    如果 Master_public_key_path 给定并指定了有效的公钥文件,则优先于 Get_master_public_key

  • Get_master_public_key

    是否向主服务器请求基于RSA密钥对的密码交换所需的公钥。 此列适用于使用 caching_sha2_password 身份验证插件 进行 身份验证的 从属 服务器。 对于该插件,除非请求,否则主服务器不会发送公钥。

    如果 Master_public_key_path 给定并指定了有效的公钥文件,则优先于 Get_master_public_key

13.7.6.35 SHOW STATUS语法

SHOW [GLOBAL | 会话]状态
    [喜欢' pattern'| 在哪里expr]

SHOW STATUS 提供服务器状态信息(请参见 第5.1.10节“服务器状态变量” )。 此声明不需要任何权限。 它只需要连接到服务器的能力。

还可以从以下来源获取状态变量信息:

对于 SHOW STATUS LIKE 子句(如果存在)指示要匹配的变量名称。 WHERE 可以使用 一个 子句来选择使用更一般条件的行,如 第25.42节“扩展显示语句”中所述

SHOW STATUS 接受可选 GLOBAL SESSION 变量范围修饰符:

  • 使用 GLOBAL 修饰符,语句将显示全局状态值。 全局状态变量可以表示服务器本身某些方面的状态(例如, Aborted_connects ),或者表示与MySQL的所有连接的聚合状态(例如, Bytes_received Bytes_sent )。 如果变量没有全局值,则显示会话值。

  • 使用 SESSION 修饰符,语句将显示当前连接的状态变量值。 如果变量没有会话值,则显示全局值。 LOCAL 是...的同义词 SESSION

  • 如果不存在修饰符,则默认为 SESSION

第5.1.10节“服务器状态变量”中 列出了每个状态变量的范围

每次调用 SHOW STATUS 语句都使用内部临时表并递增全局 Created_tmp_tables 值。

此处显示了部分输出。 您的服务器的名称和值列表可能有所不同。 第5.1.10节“服务器状态变量”中 给出了每个变量的含义

MySQL的> SHOW STATUS;
+ -------------------------- + ------------ +
| Variable_name | 价值|
+ -------------------------- + ------------ +
| Aborted_clients | 0 |
| Aborted_connects | 0 |
| Bytes_received | 155372598 |
| Bytes_sent | 1176560426 |
| 连接| 30023 |
| Created_tmp_disk_tables | 0 |
| Created_tmp_tables | 8340 |
| Created_tmp_files | 60 |
...
| Open_tables | 1 |
| Open_files | 2 |
| Open_streams | 0 |
| Opened_tables | 44600 |
| 问题| 2026873 |
...
| Table_locks_immediate | 1920382 |
| Table_locks_waited | 0 |
| Threads_cached | 0 |
| Threads_created | 30022 |
| Threads_connected | 1 |
| Threads_running | 1 |
| 正常运行时间| 80380 |
+ -------------------------- + ------------ +

使用 LIKE 子句,该语句仅显示名称与模式匹配的变量的行:

MySQL的> SHOW STATUS LIKE 'Key%';
+ -------------------- + ---------- +
| Variable_name | 价值|
+ -------------------- + ---------- +
| Key_blocks_used | 14955 |
| Key_read_requests | 96854827 |
| Key_reads | 162040 |
| Key_write_requests | 7589728 |
| Key_writes | 3813196 |
+ -------------------- + ---------- +

13.7.6.36 SHOW TABLE STATUS语法

显示表状态
    [{FROM | 在}db_name ]
    [喜欢' pattern'| 在哪里expr]

SHOW TABLE STATUS 工作喜欢 SHOW TABLES ,但提供了很多关于每个非 TEMPORARY 的信息 您还可以使用 mysqlshow --status db_name 命令 获取此列表 LIKE 子句(如果存在)指示要匹配的表名。 WHERE 子句可以使用更一般的条件来选择行,如 第25.42节“扩展到SHOW语句”中所述

此语句还显示有关视图的信息。

SHOW TABLE STATUS 输出有以下列:

  • Name

    表的名称。

  • Engine

    表的存储引擎。 请参见 第15章, InnoDB存储引擎 第16章, 备用存储引擎

    对于分区表, Engine 显示所有分区使用的存储引擎的名称。

  • Version

    此列未使用。 通过删除 .frm MySQL 8.0中 文件,此列现在报告硬编码值 10 ,这是 .frm MySQL 5.7中使用 的最后一个 文件版本。

  • Row_format

    该行的存储格式( Fixed Dynamic Compressed Redundant Compact )。 对于 MyISAM 表格, Dynamic 对应 myisamchk -dvv 报告的内容 Packed

  • Rows

    行数。 某些存储引擎(例如 MyISAM )存储确切的计数。 对于其他存储引擎,例如 InnoDB ,该值是近似值,并且可以与实际值相差多达40%至50%。 在这种情况下,用于 SELECT COUNT(*) 获得准确的计数。

    Rows 值是 NULL INFORMATION_SCHEMA 表。

    对于 InnoDB 表,行计数仅是SQL优化中使用的粗略估计。 (如果 InnoDB 表已分区, 也是如此 。)

  • Avg_row_length

    平均行长。

  • Data_length

    For MyISAM Data_length 是数据文件的长度,以字节为单位。

    For InnoDB Data_length 是为聚簇索引分配的大致内存量,以字节为单位。 具体来说,它是聚集索引大小(以页为单位)乘以 InnoDB 页面大小。

    有关其他存储引擎的信息,请参阅本节末尾的注释。

  • Max_data_length

    对于 MyISAM Max_data_length 是数据文件的最大长度。 这是在给定数据指针大小的情况下可以存储在表中的数据的总字节数。

    未使用 InnoDB

    有关其他存储引擎的信息,请参阅本节末尾的注释。

  • Index_length

    For MyISAM Index_length 是索引文件的长度,以字节为单位。

    For InnoDB Index_length 是为非聚簇索引分配的大致内存量,以字节为单位。 具体来说,它是非聚集索引大小(以页为单位)乘以 InnoDB 页面大小 的总和

    有关其他存储引擎的信息,请参阅本节末尾的注释。

  • Data_free

    已分配但未使用的字节数。

    InnoDB tables报告表所属的表空间的可用空间。 对于位于共享表空间中的表,这是共享表空间的可用空间。 如果您使用多个表空间并且该表具有自己的表空间,则可用空间仅用于该表。 可用空间表示完全空闲的区域中的字节数减去安全边界。 即使可用空间显示为0,只要不需要分配新的扩展区,就可以插入行。

    对于NDB Cluster, Data_free 显示磁盘上为磁盘数据表或磁盘分配但未使用的空间。 Data_length 报告内存数据资源使用情况 。)

    对于分区表,此值仅为估计值,可能不完全正确。 在这种情况下获取此信息的更准确方法是查询 INFORMATION_SCHEMA PARTITIONS 表,如下例所示:

    SELECT SUM(DATA_FREE)
        来自INFORMATION_SCHEMA.PARTITIONS
        WHERE TABLE_SCHEMA ='mydb'
        AND TABLE_NAME ='mytable';
    

    有关更多信息,请参见 第25.17节“INFORMATION_SCHEMA PARTITIONS表”

  • Auto_increment

    下一个 AUTO_INCREMENT 值。

  • Create_time

    创建表时。

  • Update_time

    上次更新数据文件时。 对于某些存储引擎,此值为 NULL 例如, InnoDB 在其 系统表空间中 存储多个表, 并且数据文件时间戳不适用。 即使 文件每次表 模式与每个 InnoDB 在单独的表 .ibd 文件, 改变缓冲 可以延缓写入到数据文件,因此,文件的修改时间是从最后插入的时间不同,更新或删除。 对于 MyISAM ,使用数据文件时间戳; 但是,在Windows上,更新不会更新时间戳,因此值不准确。

    Update_time 显示最后一个 UPDATE INSERT DELETE InnoDB 未分区的表上 执行 的时间戳值 对于MVCC,时间戳值反映 COMMIT 时间,该时间被视为上次更新时间。 重新启动服务器或从 InnoDB 数据字典缓存中 逐出表时,时间戳不会保留

  • Check_time

    上次检查表时。 此时并非所有存储引擎都更新,在这种情况下,值始终为 NULL

    对于分区 InnoDB 表, Check_time 总是如此 NULL

  • Collation

    表默认排序规则。 输出未显式列出表默认字符集,但排序规则名称以字符集名称开头。

  • Checksum

    实时校验和值(如果有)。

  • Create_options

    使用的额外选项 CREATE TABLE CREATE TABLE 保留了执行 when时的原始选项, 此处报告的选项可能与活动表设置和选项不同。

    对于 InnoDB 表格, 报告 实际 ROW_FORMAT KEY_BLOCK_SIZE 选项。 在MySQL 8.0之前, Create_options 报告最初提供的 ROW_FORMAT KEY_BLOCK_SIZE 有关更多信息,请参见 第13.1.20节“CREATE TABLE语法”

    Create_options 显示 partitioned 表是否已分区。 它还显示 ENCRYPTION 在创建或更改每个表的文件表空间时指定 选项。 此列不显示创建或更改常规表空间时指定的加密选项。 ENCRYPTION INNODB_TABLESPACES 适用于每个表文件和一般表空间。

  • Comment

    创建表时使用的注释(或有关MySQL无法访问表信息的信息)。

笔记
  • 对于 NDB 表,此语句的输出显示 Avg_row_length Data_length 列的 适当值,但 BLOB 不考虑列。

  • 对于 NDB 表格,仅 Data_length 包括存储在主存储器中的数据; Max_data_length Data_free 列应用到磁盘的数据。

  • 对于NDB Cluster Disk Data表, Max_data_length 显示为磁盘数据表或片段的磁盘部分分配的空间。 Data_length 报告内存数据资源使用情况 。)

  • 对于 MEMORY 表, Data_length Max_data_length ,和 Index_length 值近似分配内存的实际数量。 分配算法大量保留存储器以减少分配操作的数量。

  • 对于视图,显示的大多数列为 SHOW TABLE STATUS 0或 NULL 除了 Name 表示视图名称, Create_time 表示创建时间,并 Comment VIEW

表中还提供了 INFORMATION_SCHEMA TABLES 表信息。 请参见 第25.30节“INFORMATION_SCHEMA TABLES表”

13.7.6.37 SHOW TABLES语法

显示[扩展] [完整]表格
    [{FROM | IN}db_name ]
    [喜欢' pattern'| 在哪里expr]

SHOW TABLES 列出 TEMPORARY 给定数据库 中的非 表。 您也可以使用 mysqlshow db_name 命令 获取此列表 LIKE 子句(如果存在)指示要匹配的表名。 WHERE 子句可以使用更一般的条件来选择行,如 第25.42节“扩展到SHOW语句”中所述

LIKE 子句 执行的匹配 取决于 lower_case_table_names 系统变量 的设置

可选 EXTENDED 修饰符导致 SHOW TABLES 列出由失败 ALTER TABLE 语句 创建的隐藏表 这些临时表的名称以逗号开头, #sql 可以使用删除 DROP TABLE

此语句还列出了数据库中的所有视图。 可选的 FULL 改性剂引起 SHOW TABLES 显示与的值的第二输出列 BASE TABLE 为一个表, VIEW 用于一个视图,或 SYSTEM VIEW 为一个 INFORMATION_SCHEMA 表。

如果您没有基表或视图的权限,则它不会显示在输出 SHOW TABLES mysqlshow db_name中

表中还提供了 INFORMATION_SCHEMA TABLES 表信息。 请参见 第25.30节“INFORMATION_SCHEMA TABLES表”

13.7.6.38 SHOW TRIGGERS语法

显示触发器
    [{FROM | IN}db_name ]
    [喜欢' pattern'| 在哪里expr]

SHOW TRIGGERS 列出当前为数据库中的表定义的触发器(默认数据库,除非 FROM 给出 子句)。 此语句仅返回您具有该 TRIGGER 权限的 数据库和表的结果 LIKE 子句(如果存在)指示要匹配的表名(而不是触发器名),并使该语句显示这些表的触发器。 WHERE 子句可以使用更一般的条件来选择行,如 第25.42节“扩展到SHOW语句”中所述

对于 第24.3节“使用触发器”中 ins_sum 定义的 触发器 ,输出 SHOW TRIGGERS 如下所示:

MySQL的> SHOW TRIGGERS LIKE 'acc%'\G
*************************** 1。排******************** *******
             触发:ins_sum
               事件:插入
               表:帐户
           声明:SET @sum = @sum + NEW.amount
              时间:之前
             创建时间:2018-08-08 10:10:12.61
            sql_mode:ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,
                      NO_ZERO_IN_DATE,NO_ZERO_DATE,
                      ERROR_FOR_DIVISION_BY_ZERO,
                      NO_ENGINE_SUBSTITUTION
             定义者:我@ localhost
character_set_client:utf8mb4
collat​​ion_connection:utf8mb4_0900_ai_ci
  数据库整理:utf8mb4_0900_ai_ci

SHOW TRIGGERS 输出有以下列:

  • Trigger

    触发器的名称。

  • Event

    触发事件。 这是触发器激活的关联表上的操作类型。 值为 INSERT (插入了一行), DELETE (删除了一行)或 UPDATE (一行被修改)。

  • Table

    为其定义触发器的表。

  • Statement

    触发体; 也就是说,触发器激活时执行的语句。

  • Timing

    触发器在触发事件之前还是之后激活。 值是 BEFORE AFTER

  • Created

    创建触发器的日期和时间。 这是 TIMESTAMP(2) 触发器 值(以百分之几秒为单位)。

  • sql_mode

    创建触发器时生效的SQL模式,以及触发器执行的模式。 有关允许的值,请参见 第5.1.11节“服务器SQL模式”

  • Definer

    格式 创建触发器的用户的帐户 'user_name'@'host_name'

  • character_set_client

    character_set_client 创建触发器时系统变量 的会话值

  • collation_connection

    collation_connection 创建触发器时系统变量 的会话值

  • Database Collation

    与触发器关联的数据库的排序规则。

INFORMATION_SCHEMA TRIGGERS 表格中 也提供了触发信息 请参见 第25.34节“INFORMATION_SCHEMA TRIGGERS表”

13.7.6.39 SHOW VARIABLES语法

SHOW [GLOBAL | 会话]变量
    [喜欢' pattern'| 在哪里expr]

SHOW VARIABLES 显示MySQL系统变量的值(请参见 第5.1.8节“服务器系统变量” )。 此声明不需要任何权限。 它只需要连接到服务器的能力。

系统变量信息也可从以下来源获得:

对于 SHOW VARIABLES LIKE 子句(如果存在)指示要匹配的变量名称。 WHERE 可以使用 一个 子句来选择使用更一般条件的行,如 第25.42节“扩展显示语句”中所述

SHOW VARIABLES 接受可选 GLOBAL SESSION 变量范围修饰符:

  • 使用 GLOBAL 修饰符,语句显示全局系统变量值。 这些是用于初始化与MySQL的新连接的相应会话变量的值。 如果变量没有全局值,则不显示任何值。

  • 使用 SESSION 修饰符,语句将显示对当前连接有效的系统变量值。 如果变量没有会话值,则显示全局值。 LOCAL 是...的同义词 SESSION

  • 如果不存在修饰符,则默认为 SESSION

每个系统变量的范围在 第5.1.8节“服务器系统变量”中 列出

SHOW VARIABLES 受版本相关的显示宽度限制。 对于具有非常长值且未完全显示的变量,请将其 SELECT 用作变通方法。 例如:

SELECT @@ GLOBAL.innodb_data_file_path;

大多数系统变量可以在服务器启动时设置(只读变量,例如 version_comment 异常)。 许多可以在运行时使用该 SET 语句 进行更改 请参见 第5.1.9节“使用系统变量” 第13.7.5.1节“变量赋值的SET语法”

此处显示了部分输出。 您的服务器的名称和值列表可能有所不同。 第5.1.8节“服务器系统变量” 描述了每个变量的含义, 第5.1.1节“配置服务器” 提供了有关调整它们的信息。

MySQL的> SHOW VARIABLES;
+ -------------------------------------------- + ---- -------------------------- +
| Variable_name | 价值|
+ -------------------------------------------- + ---- -------------------------- +
| activate_all_roles_on_login | 关闭|
| auto_generate_certs | ON |
| auto_increment_increment | 1 |
| auto_increment_offset | 1 |
| 自动提交| ON |
| automatic_sp_privileges | ON |
| avoid_temporal_upgrade | 关闭|
| back_log | 151 |
| basedir | / usr / |
| big_tables | 关闭|
| bind_address | * |
| binlog_cache_size | 32768 |
| binlog_checksum | CRC32 |
| binlog_direct_non_transactional_updates | 关闭|
| binlog_error_action | ABORT_SERVER |
| binlog_expire_logs_seconds | 2592000 |
| binlog_format | 行|
| binlog_group_commit_sync_delay | 0 |
| binlog_group_commit_sync_no_delay_count | 0 |
| binlog_gtid_simple_recovery | ON |
| binlog_max_flush_queue_time | 0 |
| binlog_order_commits | ON |
| binlog_row_image | 完全|
| binlog_row_metadata | MINIMAL |
| binlog_row_value_options | |
| binlog_rows_query_log_events | 关闭|
| binlog_stmt_cache_size | 32768 |
| binlog_transaction_dependency_history_size | 25000 |
| binlog_transaction_dependency_tracking | COMMIT_ORDER |
| block_encryption_mode | aes-128-ecb |
| bulk_insert_buffer_size | 8388608 |

...

| max_allowed_pa​​cket | 67108864 |
| max_binlog_cache_size | 18446744073709547520 |
| max_binlog_size | 1073741824 |
| max_binlog_stmt_cache_size | 18446744073709547520 |
| max_connect_errors | 100 |
| max_connections | 151 |
| max_delayed_threads | 20 |
| max_digest_length | 1024 |
| max_error_count | 1024 |
| max_execution_time | 0 |
| max_heap_table_size | 16777216 |
| max_insert_delayed_threads | 20 |
| max_join_size | 18446744073709551615 |

...

| thread_handling | 每个连接一个线程
| thread_stack | 286720 |
| time_zone | 系统|
| 时间戳| 1530906638.765316 |
| tls_version | TLSv1,TLSv1.1,TLSv1.2 |
| tmp_table_size | 16777216 |
| tmpdir | / tmp |
| transaction_alloc_block_size | 8192 |
| transaction_allow_batching | 关闭|
| transaction_isolation | REPEATABLE-READ |
| transaction_prealloc_size | 4096 |
| transaction_read_only | 关闭|
| transaction_write_set_extraction | XXHASH64 |
| unique_checks | ON |
| updatable_views_with_limit | 是的|
| 版本| 8.0.12 |
| version_comment | MySQL社区服务器 -  GPL |
| version_compile_machine | x86_64 |
| version_compile_os | Linux |
| version_compile_zlib | 1.2.11 |
| wait_timeout | 28800 |
| warning_count | 0 |
| windowing_use_high_precision | ON |
+ -------------------------------------------- + ---- -------------------------- +

使用 LIKE 子句,该语句仅显示名称与模式匹配的变量的行。 要获取特定变量的行,请使用 LIKE 如下所示 子句:

显示变量如'max_join_size';
显示会话变量类似'max_join_size';

要获取名称与模式匹配的变量列表,请 % LIKE 子句中 使用 通配符

显示变量如'%size%';
显示全球变量如'%size%';

通配符可用于要匹配的模式中的任何位置。 严格来说,因为 _ 是一个匹配任何单个字符的通配符,你应该将其转义为 \_ 按字面意思匹配它。 实际上,这很少是必要的。

13.7.6.40 SHOW WARNINGS语法

显示警告[限制[ offset,] row_count]
显示计数(*)警告

SHOW WARNINGS 是一个诊断语句,显示有关在当前会话中执行语句所产生的条件(错误,警告和注释)的信息。 警告DML语句诸如产生 INSERT UPDATE LOAD DATA 以及DDL语句如 CREATE TABLE ALTER TABLE

LIMIT 子句的语法与 SELECT 语句 相同 请参见 第13.2.10节“SELECT语法”

SHOW WARNINGS 也用于以下 EXPLAIN ,以显示由其生成的扩展信息 EXPLAIN 请参见 第8.8.3节“扩展EXPLAIN输出格式”

SHOW WARNINGS 显示有关在当前会话中执行最近的非诊断语句所导致的条件的信息。 如果最新语句在解析期间导致错误,则 SHOW WARNINGS 显示结果条件,而不管语句类型(诊断或非诊断)。

SHOW COUNT(*) WARNINGS 诊断语句显示错误,警告和注意事项的总数。 您还可以从 warning_count 系统变量中 检索此数字

显示计数(*)警告;
SELECT @@ warning_count;

这些语句的区别在于第一个是不清除消息列表的诊断语句。 第二个,因为它是一个 SELECT 声明被认为是非诊断的并且确实清除了消息列表。

相关的诊断语句 SHOW ERRORS 仅显示错误条件(不包括警告和注释),并且 SHOW COUNT(*) ERRORS 语句显示错误总数。 请参见 第13.7.6.17节“显示错误语法” GET DIAGNOSTICS 可用于检查个别条件的信息。 请参见 第13.6.7.3节“获取诊断语法”

这是一个显示数据转换警告的简单示例 INSERT 该示例假定禁用严格的SQL模式。 启用严格模式后,警告将成为错误并终止 INSERT

MySQL的> CREATE TABLE t1 (a TINYINT NOT NULL, b CHAR(4));
查询OK,0行受影响(0.05秒)

MySQL的> INSERT INTO t1 VALUES(10,'mysql'), (NULL,'test'), (300,'xyz');
查询正常,3行受影响,3次警告(0.00秒)
记录:3个重复:0个警告:3

MySQL的> SHOW WARNINGS\G
*************************** 1。排******************** *******
  等级:警告
   代码:1265
消息:第1行的列'b'截断数据
*************************** 2.排******************** *******
  等级:警告
   代码:1048
消息:列'a'不能为空
*************************** 3。排******************** *******
  等级:警告
   代码:1264
消息:第3行的列'a'超出范围值
3组(0.00秒)

所述 max_error_count 系统变量控制错误,警告和音符信息的最大数量的量,服务器存储的信息,因此该消息数 SHOW WARNINGS 显示。 要更改服务器可以存储的消息数,请更改值 max_error_count

max_error_count 仅控制存储的消息数量,而不是计算的消息数量。 即使生成的消息数超过, warning_count 也不受限制 以下示例演示了这一点。 语句产生三条警告消息(示例禁用严格的SQL模式以防止在单个转换问题后发生错误)。 只存储并显示一条消息,因为 已设置为1,但所有三条都被计算在内(如值所示 ): max_error_count max_error_count ALTER TABLE max_error_count warning_count

MySQL的> SHOW VARIABLES LIKE 'max_error_count';
+ ----------------- + ------- +
| Variable_name | 价值|
+ ----------------- + ------- +
| max_error_count | 1024 |
+ ----------------- + ------- +
1排(0.00秒)

MySQL的> SET max_error_count=1, sql_mode = '';
查询正常,0行受影响(0.00秒)

MySQL的> ALTER TABLE t1 MODIFY b CHAR;
查询正常,3行受影响,3次警告(0.00秒)
记录:3个重复:0个警告:3

MySQL的> SHOW WARNINGS;
+ --------- + ------ + -------------------------------- -------- +
| 等级| 代码| 消息|
+ --------- + ------ + -------------------------------- -------- +
| 警告| 1263 | 第1行的列'b'截断数据
+ --------- + ------ + -------------------------------- -------- +
1排(0.00秒)

MySQL的> SELECT @@warning_count;
+ ----------------- +
| @@ warning_count |
+ ----------------- +
| 3 |
+ ----------------- +
1排(0.01秒)

要禁用消息存储,请设置 max_error_count 为0.在这种情况下, warning_count 仍指示发生了多少警告,但消息未存储且无法显示。

sql_notes 系统变量控制是否说明消息增量 warning_count 和服务器是否将它们存储。 默认情况下, sql_notes 为1,但如果设置为0,则注释不会递增 warning_count ,服务器不会存储它们:

mysql> SET sql_notes = 1;
mysql>DROP TABLE IF EXISTS test.no_such_table;
查询正常,0行受影响,1警告(0.00秒)
MySQL的> SHOW WARNINGS;
+ ------- + ------ + ---------------------------------- -  +
| 等级| 代码| 消息|
+ ------- + ------ + ---------------------------------- -  +
| 注意| 1051 | 未知表'test.no_such_table'|
+ ------- + ------ + ---------------------------------- -  +
1排(0.00秒)

mysql> SET sql_notes = 0;
mysql>DROP TABLE IF EXISTS test.no_such_table;
查询正常,0行受影响(0.00秒)
MySQL的> SHOW WARNINGS;
空集(0.00秒)

MySQL服务器向每个客户端发送一个计数,指示由该客户端执行的最新语句产生的错误,警告和注释的总数。 从C API,可以通过调用获得此值 mysql_warning_count() 请参见 第28.7.7.82节“mysql_warning_count()”

MySQL的 客户端,您可以启用和禁用使用自动的警告显示 warnings nowarning 分别命令,或它们的快捷键, \W \w (参见 第4.5.1.2节,“MySQL客户端命令” )。 例如:

MySQL的> \W
显示警告已启用。
MySQL的> SELECT 1/0;
+ ------ +
| 1/0 |
+ ------ +
| NULL |
+ ------ +
1排,1警告(0.03秒)

警告(代码1365):除以0
MySQL的> \w
显示警告已禁用。

13.7.7其他行政声明

13.7.7.1 BINLOG语法

BINLOG' str'

BINLOG 是一个内部使用声明。 它由 mysqlbinlog 程序 生成, 作为二进制日志文件中某些事件的可打印表示。 (请参见 第4.6.8节“ mysqlbinlog - 处理二进制日志文件的实用程序” 。)该 值是一个基本的64位编码字符串,该服务器解码该字符串以确定相应事件指示的数据更改。 此声明需要 特权。 'str' BINLOG_ADMIN SUPER

此语句只能执行格式描述事件和行事件。

13.7.7.2 CACHE INDEX语法

CACHE INDEX {
       tbl_index_list[,tbl_index_list] ......
    | tbl_name分区(partition_list
  }key_cache_name

tbl_index_listtbl_name[{INDEX | KEY}(index_name[,index_name] ...)]

partition_list:{
     partition_name[,partition_name] ......
  | 所有
}

CACHE INDEX 语句将表索引分配给特定的键缓存。 它仅适用于 MyISAM 表,包括分区 MyISAM 表。 分配索引后,可以根据需要将它们预加载到缓存中 LOAD INDEX INTO CACHE

下面的语句从表中分配指标 t1 t2 以及 t3 名为键缓存 hot_cache

MySQL的> CACHE INDEX t1, t2, t3 IN hot_cache;
+ --------- + -------------------- + ---------- + ------- --- +
| 表| Op | Msg_type | Msg_text |
+ --------- + -------------------- + ---------- + ------- --- +
| test.t1 | assign_to_keycache | 状态| 好的
| test.t2 | assign_to_keycache | 状态| 好的
| test.t3 | assign_to_keycache | 状态| 好的
+ --------- + -------------------- + ---------- + ------- --- +

语法 CACHE INDEX 使您可以指定只应将表中的特定索引分配给缓存。 但是,实现将所有表的索引分配给缓存,因此没有理由指定除表名之外的任何内容。

CACHE INDEX 可以通过使用参数设置语句或服务器参数设置设置其大小来创建语句中 引用的键高速缓存 例如:

SET GLOBAL keycache1.key_buffer_size = 128 * 1024;

密钥缓存参数作为结构化系统变量的成员进行访问。 请参见 第5.1.9.5节“结构化系统变量”

在为其分配索引或发生错误之前,必须存在密钥缓存:

MySQL的> CACHE INDEX t1 IN non_existent_cache;
ERROR 1284(HY000):未知密钥缓存'non_existent_cache'

默认情况下,表索引分配给在服务器启动时创建的主(默认)密钥缓存。 销毁密钥缓存时,分配给它的所有索引都将重新分配给默认密钥缓存。

索引分配会全局影响服务器:如果一个客户端为给定缓存分配索引,则无论哪个客户端发出查询,此缓存都将用于涉及索引的所有查询。

CACHE INDEX 分区 MyISAM 支持 您可以将一个,多个或所有分区的一个或多个索引分配给给定的密钥缓存。 例如,您可以执行以下操作:

CREATE TABLE pt(c1 INT,c2 VARCHAR(50),INDEX i(c1))
    ENGINE = MyISAM数据
    哈希分区(c1)
    PARTITIONS 4;

SET GLOBAL kc_fast.key_buffer_size = 128 * 1024;
SET GLOBAL kc_slow.key_buffer_size = 128 * 1024;

CACHE INDEX pt PARTITION(p0)IN kc_fast;
CACHE INDEX pt PARTITION(p1,p3)IN kc_slow;

上一组语句执行以下操作:

  • 创建一个包含4个分区的分区表; 这些分区自动命名 p0 ,... , p3 ; 此表有一个以 i 命名的索引 c1

  • 创建名为 kc_fast 和的 2个密钥缓存 kc_slow

  • 分配为分区的索引 p0 kc_fast 键缓存和用于分区的索引 p1 p3 kc_slow 键缓存; 剩余分区( p2 的索引 使用服务器的默认密钥缓存。

如果您希望将表中所有分区的索引分配给 pt 名为的单个密钥缓存 kc_all ,则可以使用以下两个语句之一:

CACH指数pt PARTITION(ALL)in kc_all;

CACHE INDEX pt IN kc_all;

刚刚显示的两个语句是等效的,发出任何一个语句都具有完全相同的效果。 换句话说,如果您希望将分区表的所有分区的索引分配给相同的密钥缓存,则该 PARTITION (ALL) 子句是可选的。

将多个分区的索引分配给密钥缓存时,分区不必是连续的,您无需按任何特定顺序列出其名称。 未明确分配给密钥缓存的任何分区的索引会自动使用服务器默认密钥缓存。

分区 MyISAM 也支持索引预加载 有关更多信息,请参见 第13.7.7.5节“LOAD INDEX INTO CACHE语法”

13.7.7.3 FLUSH语法

FLUSH [NO_WRITE_TO_BINLOG | LOCAL] {
     flush_option[,flush_option] ......
  | tables_option
}

flush_option:{
    二进制日志
  | 发动机日志
  | 错误日志
  | 一般日志
  | HOSTS
  | 日志
  | 特权
  | OPTIMIZER_COSTS
  | 继电器日志[FOR CHANNEL channel]
  | 慢日志
  | 状态
  | USER_RESOURCES
}

tables_option:{
    TABLES
  | 表格tbl_name[,tbl_name] ......
  | 带读锁的表格
  | TABLES tbl_name[,tbl_name] ......阅读锁定
  | TABLES tbl_name[,tbl_name] ......出口
}

FLUSH 语句有几种变体形式,用于清除或重新加载各种内部高速缓存,刷新表或获取锁。 要执行 FLUSH ,您必须拥有该 RELOAD 权限。 特定刷新选项可能需要其他权限,如稍后所述。

注意

无法 FLUSH 在存储的函数或触发器中 发出 语句。 但是,您可以 FLUSH 在存储过程中 使用 ,只要不从存储的函数或触发器调用它们。 请参见 第C.1节“存储程序的限制”

默认情况下,服务器将 FLUSH 语句 写入 二进制日志,以便它们复制到复制从属服务器。 要禁止记录,请指定可选 NO_WRITE_TO_BINLOG 关键字或其别名 LOCAL

注意

FLUSH LOGS FLUSH BINARY LOGS FLUSH TABLES WITH READ LOCK (带或不带表列表),并 没有写入到二进制日志在任何情况下,因为如果复制到从它们会造成问题。 FLUSH TABLES tbl_name ... FOR EXPORT

FLUSH 语句导致隐式提交。 请参见 第13.3.3节“导致隐式提交的语句”

所述 中mysqladmin 实用程序提供了一个命令行界面一些刷新操作,使用诸如命令 flush-hosts flush-logs flush-privileges flush-status ,和 flush-tables 请参见 第4.5.2节“ mysqladmin - 管理MySQL服务器的客户端”

SIGHUP 服务器 发送 信号会导致发生几次与各种形式的 FLUSH 语句 类似的刷新操作 请参见 第5.1.16节“服务器对信号的响应”

RESET 声明是相似 FLUSH 有关 语句与复制一起 使用的信息 请参见 第13.7.7.6节“RESET语法” RESET

以下列表描述了允许的 FLUSH 语句 flush_option 值。 有关 FLUSH TABLES 变体的 描述 ,请参见 FLUSH TABLES语法

  • FLUSH BINARY LOGS

    关闭并重新打开服务器正在写入的任何二进制日志文件。 如果启用了二进制日志记录,则二进制日志文件的序列号相对于前一个文件递增1。

  • FLUSH ENGINE LOGS

    关闭并重新打开已安装存储引擎的任何可刷新日志。 这会导致 InnoDB 将其日志刷新到磁盘。

  • FLUSH ERROR LOGS

    关闭并重新打开服务器正在写入的任何错误日志文件。

  • FLUSH GENERAL LOGS

    关闭并重新打开服务器正在写入的任何常规查询日志文件。

  • FLUSH HOSTS

    清空主机缓存和 host_cache 公开缓存内容 的性能模式 表,并取消阻止任何被阻止的主机。 请参见 第8.12.4.2节“DNS查找优化和主机缓存”

    如果某些主机更改了IP地址,或者 对于来自合法主机的连接发生 错误消息,请刷新主机缓存 (参见 第B.4.2.5节“主机'host_name'被阻止” 。)当 连接到MySQL服务器时,当给定主机连续发生错误时,MySQL认为出现了问题,并阻止主机进一步连接请求。 刷新主机缓存会启用来自主机的进一步连接尝试。 默认值为 100.要避免此错误消息,请启动服务器并将其 设置为较大的值。 Host 'host_name' is blocked max_connect_errors max_connect_errors max_connect_errors

  • FLUSH LOGS

    关闭并重新打开服务器正在写入的任何日志文件。 如果启用了二进制日志记录,则二进制日志文件的序列号相对于前一个文件递增1。 如果启用了中继日志记录,则中继日志文件的序列号相对于前一个文件递增1。

    FLUSH LOGS 对用于常规查询日志或慢查询日志的表没有影响(请参见 第5.4.1节“选择常规查询日志和慢查询日志输出目标” )。

  • FLUSH OPTIMIZER_COSTS

    重新读取成本模型表,以便优化程序开始使用存储在其中的当前成本估算。 服务器会向错误日志写入警告,以查找任何无法识别的条目。 (有关这些表的信息,请参见 第8.9.5节“优化程序成本模型” 。)此操作仅影响在刷新后开始的会话。 现有会议继续使用开始时的当前成本估算。

  • FLUSH PRIVILEGES

    mysql 系统数据库中 的授权表重新加载特权 ,并清除 caching_sha2_password 身份验证插件 使用的内存高速缓存

    作为此操作的一部分,服务器将读取 global_grants 包含动态权限分配 表,并注册其中发现的任何未注册权限。

    服务器在内存中缓存信息的结果 GRANT CREATE USER CREATE SERVER ,和 INSTALL PLUGIN 语句。 该内存不能由相应的释放 REVOKE DROP USER DROP SERVER ,和 UNINSTALL PLUGIN 语句,所以执行导致缓存报表的多个实例的服务器上,将有内存使用的增加。 可以释放此缓存的内存 FLUSH PRIVILEGES

  • FLUSH RELAY LOGS [FOR CHANNEL channel]

    关闭并重新打开服务器正在写入的任何中继日志文件。 如果启用了中继日志记录,则中继日志文件的序列号相对于前一个文件递增1。

    子句使您可以命名该语句适用的复制通道。 执行 以刷新特定复制通道的中继日志。 如果未命名通道且不存在额外的复制通道,则该语句将应用于默认通道。 如果未命名通道且存在多个复制通道,则该语句将应用于所有复制通道。 有关更多信息,请参见 第17.2.3节“复制通道” FOR CHANNEL channel FLUSH RELAY LOGS FOR CHANNEL channel

  • FLUSH SLOW LOGS

    关闭并重新打开服务器正在写入的任何慢查询日志文件。

  • FLUSH STATUS

    此选项将会话状态从所有活动会话添加到全局状态变量,重置所有活动会话的状态,并重置从断开连接的会话聚合的帐户,主机和用户状态值。 请参见 第26.12.14节“性能模式状态变量表” 调试查询时,此信息可能有用。 请参见 第1.7节“如何报告错误或问题”

  • FLUSH USER_RESOURCES

    将所有每小时用户资源重置为零。 这使已达到每小时连接,查询或更新限制的客户端能够立即恢复活动。 FLUSH USER_RESOURCES 不适用于由 max_user_connections 系统变量 控制的最大同时连接的限制 请参见 第6.2.20节“设置帐户资源限制”

FLUSH TABLES语法

FLUSH TABLES 刷新表,并根据使用的变量获取锁。 声明中 TABLES 使用的 任何 变体 FLUSH 必须是唯一使用的选项。 FLUSH TABLE 是...的同义词 FLUSH TABLES

注意

此处的说明指示表通过关闭它们以不同的方式 InnoDB 刷新,这会将表内容刷新到磁盘但保持打开状态。 这仍然允许在表打开时复制表文件,只要其他活动不修改它们即可。

  • FLUSH TABLES

    关闭所有打开的表,强制关闭所有正在使用的表,并刷新预准备的语句缓存。 有关 准备语句高速缓存的信息,请参见 第8.10.3节“高速缓存准备语句和存储程序”

    FLUSH TABLES 有活动时不允许 LOCK TABLES ... READ 要刷新和锁定表,请 改用。 FLUSH TABLES tbl_name ... WITH READ LOCK

  • FLUSH TABLES tbl_name [, tbl_name] ...

    使用一个或多个以逗号分隔的表名列表,此语句 FLUSH TABLES 与没有名称的 情况类似 ,只是服务器只刷新命名表。 如果命名表不存在,则不会发生错误。

  • FLUSH TABLES WITH READ LOCK

    关闭所有打开的表并使用全局读锁锁定所有数据库的所有表。 如果您具有可以及时拍摄快照的Veritas或ZFS等文件系统,则这是一种非常方便的备份方式。 使用 UNLOCK TABLES 即可解除锁定。

    FLUSH TABLES WITH READ LOCK 获得全局读锁定,而不是表锁,所以它不会受到相同的行为 LOCK TABLES ,并 UNLOCK TABLES 相对于表锁定和隐式的提交:

    FLUSH TABLES WITH READ LOCK 不会阻止服务器将行插入日志表(请参见 第5.4.1节“选择常规查询日志和慢查询日志输出目标” )。

  • FLUSH TABLES tbl_name [, tbl_name] ... WITH READ LOCK

    此语句刷新并获取指定表的读锁定。 该语句首先获取表的独占元数据锁,因此它等待打开这些表的事务完成。 然后,语句从表缓存中刷新表,重新打开表,获取表锁(如 LOCK TABLES ... READ ),并将元数据锁从独占降级为共享。 在语句获取锁并降级元数据锁之后,其他会话可以读取但不能修改表。

    由于此语句获取表锁,因此 LOCK TABLES 除了 RELOAD 使用任何 FLUSH 语句 所需 权限 之外 ,还必须具有 每个表的 权限

    此语句仅适用于现有基 TEMPORARY) (非 表。如果名称引用基表,则使用该表。如果引用 TEMPORARY 表,则忽略 表。如果名称适用于视图, ER_WRONG_OBJECT 则会发生错误。否则,发生 ER_NO_SUCH_TABLE 错误。

    使用 UNLOCK TABLES 释放锁, LOCK TABLES 以释放锁和收购其他的锁,或 START TRANSACTION 释放锁,并开始一个新的事务。

    FLUSH TABLES 变体使表能够在单个操作中刷新和锁定。 它为 FLUSH TABLES 有活动时不允许 的限制提供了一种解决方法 LOCK TABLES ... READ

    此语句不执行隐式 UNLOCK TABLES ,因此如果在有活动时使用该语句,则会导致错误, LOCK TABLES 或者在未首先释放获取的锁定的情况下再次 使用该语句时会导致错误

    如果打开了刷新的表 HANDLER ,则会隐式刷新处理程序并丢失其位置。

  • FLUSH TABLES tbl_name [, tbl_name] ... FOR EXPORT

    FLUSH TABLES 变体适用于 InnoDB 表格。 它确保已将对指定表的更改刷新到磁盘,以便在服务器运行时可以创建二进制表副本。

    声明的作用如下:

    1. 它获取指定表的共享元数据锁。 只要其他会话具有已修改这些表或为其保存表锁的活动事务,该语句就会阻塞。 获取锁后,该语句将阻止尝试更新表的事务,同时允许只读操作继续。

    2. 它检查表的所有存储引擎是否支持 FOR EXPORT 如果没有,则发生 ER_ILLEGAL_HA 错误并且语句失败。

    3. 该语句通知存储引擎每个表以使表准备好导出。 存储引擎必须确保将所有挂起的更改写入磁盘。

    4. 该语句将会话置于锁定表模式,以便在 FOR EXPORT 语句完成 时不会释放先前获取的元数据锁

    FLUSH TABLES ... FOR EXPORT 声明要求您拥有 SELECT 每个表 权限。 由于此语句获取表锁,因此 LOCK TABLES 除了 RELOAD 使用任何 FLUSH 语句 所需 权限 之外 ,还必须具有 每个表的 权限

    此语句仅适用于现有的基(非 TEMPORARY )表。 如果名称引用基表,则使用该表。 如果它引用 TEMPORARY 表,则忽略它。 如果名称适用于视图, ER_WRONG_OBJECT 则会发生错误。 否则, ER_NO_SUCH_TABLE 会发生错误。

    InnoDB 支持 FOR EXPORT 具有自己的 .ibd 文件 文件的表(即,在 innodb_file_per_table 启用设置的情况下 创建的表 )。 InnoDB 确保在 FOR EXPORT 语句 通知 任何更改已刷新到磁盘时。 这允许在 FOR EXPORT 语句生效 时生成表内容的二进制副本, 因为该 .ibd 文件是事务一致的,并且可以在服务器运行时复制。 FOR EXPORT 不适用于 InnoDB 系统表空间文件或 InnoDB 具有 FULLTEXT 索引的

    FLUSH TABLES ...FOR EXPORT 分区 InnoDB 支持

    通知时 FOR EXPORT InnoDB 将某些类型的数据写入磁盘,这些数据通常保存在内存中或表空间文件外的单独磁盘缓冲区中。 对于每个表, InnoDB 还会生成一个 table_name.cfg 与该表位于同一数据库目录中的 文件 .cfg 文件包含稍后将表空间文件重新导入相同或不同服务器所需的元数据。

    FOR EXPORT 语句完成, InnoDB 将有刷新所有 脏页 表中的数据文件。 在刷新之前合并 任何 更改缓冲区 条目。 此时,表已锁定且处于静止状态:表在磁盘上处于事务一致状态,您可以将 .ibd 表空间文件与相应 .cfg 文件 一起 复制, 以获得这些表的一致快照。

    有关将复制的表数据重新导入MySQL实例的过程,请参见 第15.6.3.7节“将表空间复制到另一个实例”

    完成表后,使用 UNLOCK TABLES 释放锁, LOCK TABLES 释放锁并获取其他锁,或 START TRANSACTION 释放锁并开始新事务。

    虽然这些语句中的任何一个在会话中都有效,但尝试使用会 FLUSH TABLES ... FOR EXPORT 产生错误:

    FLUSH TABLES ...阅读锁定
    FLUSH TABLES ...出口
    LOCK TABLES ...阅读
    LOCK TABLES ...写
    

    虽然 FLUSH TABLES ... FOR EXPORT 在会话中有效,但尝试使用这些语句中的任何一个都会产生错误:

    带读锁的冲洗表
    FLUSH TABLES ...阅读锁定
    FLUSH TABLES ...出口
    

13.7.7.4 KILL语法

杀[连接| QUERY]processlist_id

mysqld的 每个连接都 在一个单独的线程中运行。 你可以用 语句 杀死一个线程 KILL processlist_id

可以从 表的 列, 输出 列和Performance Schema ID 确定线程进程列表标识符 函数 返回当前线程的值 INFORMATION_SCHEMA PROCESSLIST Id SHOW PROCESSLIST PROCESSLIST_ID threads CONNECTION_ID()

KILL 允许使用可选 CONNECTION QUERY 修饰符:

  • KILL CONNECTION KILL 与没有修饰符 相同 :它终止 processlist_id 连接正在执行的任何语句后终止 与给定关联 的连接。

  • KILL QUERY 终止连接当前正在执行的语句,但保持连接本身不变。

查看哪些线程可以被杀死的能力取决于 PROCESS 权限:

  • 没有 PROCESS ,你只能看到你自己的线程。

  • 有了 PROCESS ,你可以看到所有线程。

杀死线程和语句的能力取决于 CONNECTION_ADMIN SUPER 特权:

您还可以使用 mysqladmin processlist mysqladmin kill 命令来检查和终止线程。

使用时 KILL ,为线程设置特定于线程的kill标志。 在大多数情况下,线程可能需要一些时间才能死掉,因为只在特定的时间间隔检查kill标志:

  • SELECT 操作 期间 ,for ORDER BY GROUP BY 循环,在读取行块之后检查标志。 如果设置了kill标志,则语句将中止。

  • ALTER TABLE 制作表副本的操作会定期检查从原始表中读取的每个复制行的kill标志。 如果设置了kill标志,则语句将中止,并删除临时表。

    KILL 语句返回时无需等待确认,但kill flag check会在相当短的时间内中止操作。 中止操作以执行任何必要的清理也需要一些时间。

  • 执行 期间 UPDATE DELETE 操作 期间 ,在每个块读取之后以及每个更新或删除的行之后检查终止标志。 如果设置了kill标志,则语句将中止。 如果您不使用事务,则不会回滚更改。

  • GET_LOCK() 中止和返回 NULL

  • 如果线程在表锁处理程序(状态 Locked :)中,表锁将快速中止。

  • 如果线程正在等待写入调用中的可用磁盘空间,则写入将中止,并显示 磁盘已满 错误消息。

警告

执行 REPAIR TABLE OPTIMIZE TABLE 操作会 MyISAM 导致表被破坏且无法使用。 对此类表的任何读取或写入都会失败,直到您再次优化或修复它(不中断)。

13.7.7.5 LOAD INDEX INTO CACHE语法

LOAD INDEX INTO CACHE
   tbl_index_list[,tbl_index_list] ......

tbl_index_listtbl_name
    [PARTITION(partition_list)]
    [{INDEX | KEY}(index_name[,index_name] ...)]
    [IGNORE LEAVES]

partition_list:{
     partition_name[,partition_name] ......
  | 所有
}

LOAD INDEX INTO CACHE 语句将表索引预加载到由显式 CACHE INDEX 语句 分配给它的密钥缓存中,否则加载 到默认密钥缓存中。

LOAD INDEX INTO CACHE 仅适用于 MyISAM 表,包括分区 MyISAM 表。 此外,可以为一个,多个或所有分区预加载分区表上的索引。

所述 IGNORE LEAVES 改性剂导致要预装只为索引的非叶结点的块。

IGNORE LEAVES 分区 MyISAM 也支持

以下语句预加载表的索引节点(索引块), t1 并且 t2

MySQL的> LOAD INDEX INTO CACHE t1, t2 IGNORE LEAVES;
+ --------- + -------------- + ---------- + ---------- +
| 表| Op | Msg_type | Msg_text |
+ --------- + -------------- + ---------- + ---------- +
| test.t1 | preload_keys | 状态| 好的
| test.t2 | preload_keys | 状态| 好的
+ --------- + -------------- + ---------- + ---------- +

此语句预加载所有索引块 t1 它仅为非叶节点预加载块 t2

语法 LOAD INDEX INTO CACHE 使您可以指定只预加载表中的特定索引。 但是,实现会将所有表的索引预加载到缓存中,因此没有理由指定除表名之外的任何内容。

可以在分区 MyISAM 表的 特定分区上预加载索引 例如,在以下两个语句中,第一个预加载 p0 分区表 分区 索引 pt ,而第二个预加载分区 p1 p3 同一个表 的索引

负荷指数进入CACHE pt PARTITION(p0);
负荷指数进入CACHE pt PARTITION(p1,p3);

要为表中的所有分区预加载索引 pt ,可以使用以下两个语句之一:

负荷指数进入CACHE pt PARTITION(全部);

LOAD INDEX INTO CACHE pt;

刚刚显示的两个语句是等效的,发出任何一个语句都具有完全相同的效果。 换句话说,如果您希望为分区表的所有分区预加载索引,则该 PARTITION (ALL) 子句是可选的。

在为多个分区预加载索引时,分区不需要是连续的,您无需按任何特定顺序列出其名称。

LOAD INDEX INTO CACHE ... IGNORE LEAVES 除非表中的所有索引具有相同的块大小,否则将失败。 要确定表的索引块大小,请使用 myisamchk -dv 并检查 Blocksize 列。

13.7.7.6 RESET语法

重置reset_option[,reset_option] ......

reset_option:{
  | 奴隶
}

RESET 语句用于清除各种服务器操作的状态。 您必须具有 RELOAD 执行权限 RESET

有关 RESET PERSIST 删除持久性全局系统变量 语句的 信息 ,请参见 第13.7.7.7节“重置PERSIST语法”

RESET 充当 FLUSH 声明 的更强版本 请参见 第13.7.7.3节“FLUSH语法”

RESET 语句导致隐式提交。 请参见 第13.3.3节“导致隐式提交的语句”

以下列表描述了允许的 RESET 语句 reset_option 值:

  • RESET MASTER

    删除索引文件中列出的所有二进制日志,将二进制日志索引文件重置为空,并创建新的二进制日志文件。

  • RESET SLAVE

    使从属服务器忘记其在主二进制日志中的复制位置。 还通过删除任何现有的中继日志文件并开始新的日志文件来重置中继日志。

13.7.7.7重置PERSIST语法

重置持有人[[如果存在] system_var_name]

RESET PERSIST mysqld-auto.cnf 数据目录中 选项文件中 删除持久化的全局系统变量设置 删除持久化系统变量会导致 mysqld-auto.cnf 在服务器启动时 不再初始化变量 有关保持系统变量和 mysqld-auto.cnf 文件的 更多信息 ,请参见 第5.1.9.3节“持久系统变量”

所需的权限 RESET PERSIST 取决于要删除的系统变量的类型:

请参见 第5.1.9.1节“系统变量权限”

根据变量名和 IF EXISTS 子句是否存在, RESET PERSIST 语句具有以下形式:

  • 要从中删除所有持久变量 mysqld-auto.cnf ,请在 RESET PERSIST 不命名任何系统变量的情况下 使用

    重置持有人;
    

    如果 mysqld-auto.cnf 包含两种 变量,则必须具有删除动态和只读系统变量的权限

  • 要从中删除特定的持久变量 mysqld-auto.cnf ,请在语句中对其进行命名:

    重置持有人system_var_name;
    

    这包括插件系统变量,即使当前未安装插件也是如此。 如果文件中不存在该变量,则会发生错误。

  • 要从文件中删除特定的持久变量 mysqld-auto.cnf ,但如果文件中不存在该变量,则产生警告而不是错误 IF EXISTS ,请在以前的语法中 添加一个 子句:

    如果存在,重置持续system_var_name;
    

RESET PERSIST 不受 persisted_globals_load 系统变量 值的影响

RESET PERSIST 影响性能模式 persisted_variables 的内容, 因为表内容对应于 mysqld-auto.cnf 文件 的内容 另一方面,因为 RESET PERSIST 不更改变量值,所以在 variables_info 重新启动服务器之前 ,它对Performance Schema 的内容没有影响

有关 RESET 清除其他服务器操作状态的语句变体的 信息 ,请参见 第13.7.7.6节“RESET语法”

13.7.7.8 RESTART语法

重新开始

该语句停止并重新启动MySQL服务器。 它需要 SHUTDOWN 特权。

一种用途 RESTART 是当不可能或不方便获得对服务器主机上的MySQL服务器的命令行访问权以重新启动它。 例如, SET PERSIST_ONLY 可以在运行时使用以对系统变量进行配置更改,这些变量只能在服务器启动时设置,但仍必须重新启动服务器才能使这些更改生效。 RESTART 语句提供了一种在客户端会话中执行此操作的方法,无需在服务器主机上进行命令行访问。

注意

执行 RESTART 语句后,客户端可能会丢失当前连接。 如果启用了自动重新连接,则在服务器重新启动后将重新建立连接。 否则,必须手动重新建立连接。

成功的 RESTART 操作要求 mysqld 在具有监视进程的环境中运行,以检测为重新启动目的而执行的服务器关闭:

  • 在存在监视进程的情况下, RESTART 导致 mysqld 终止,以便监视进程可以确定它应该启动一个新的 mysqld 实例。

  • 如果没有监视进程,则会 RESTART 失败并显示错误。

这些平台为 RESTART 语句 提供必要的监视支持

  • Windows,当 mysqld 作为Windows服务或独立启动 mysqld forks,一个进程充当另一个进程的监视器,充当服务器。)

  • Unix和类Unix系统使用systemd或 mysqld_safe 来管理 mysqld

要配置监视环境,以便 mysqld 启用该 RESTART 语句:

  1. 在设置 MYSQLD_PARENT_PID 环境变量设置进程的进程ID的启动值 的mysqld ,启动前 的mysqld

  2. mysqld 由于使用该 RESTART 语句 而执行关闭时 ,它将返回退出代码16。

  3. 当监视进程检测到退出代码为16时,它会 再次 启动 mysqld 否则,它会退出。

这是在 bash shell中 实现的最小示例

#!/斌/庆典

export MYSQLD_PARENT_PID = $$

export MYSQLD_RESTART_EXIT = 16

而真实; 
  斌/ mysqld的 mysqld options here
  如果[$?-ne $ MYSQLD_RESTART_EXIT]; 然后
    打破
  科幻
DONE

在Windows上,用于实现的分叉 RESTART 使得确定要附加的服务器进程以进行调试更加困难。 为了缓解这种情况, --gdb 除了为设置调试环境所做的其他操作外,还要 使用 抑制分叉来 启动服务器 在非调试设置中, --no-monitor 可以仅用于抑制分支监视过程的唯一目的。 对于服务器开始无论是 --gdb --no-monitor ,执行 RESTART 导致服务器只是退出无需重新启动。

13.7.7.9 SHUTDOWN语法

关掉

该语句停止MySQL服务器。 它需要 SHUTDOWN 特权。

SHUTDOWN 为使用 mysqladmin shutdown 命令 提供的相同功能提供SQL级接口

13.8效用声明

13.8.1 DESCRIBE语法

DESCRIBE EXPLAIN 语句是同义词,或者用于获取有关表结构或查询执行计划的信息。 有关更多信息,请参见 第13.7.6.5节“显示列语法” 第13.8.2节“EXPLAIN语法”

13.8.2 EXPLAIN语法

{EXPLAIN | 描述| DESC}
     tbl_name[ col_name| wild]

{EXPLAIN | 描述| DESC}
    [ explain_type]
    { explainable_stmt| 用于连接connection_id}

explain_type:{
    格式= format_name
}

format_name:{
    传统
  | JSON
  | 
}

explainable_stmt:{
    SELECT语句
  | DELETE语句
  | INSERT语句
  | REPLACE声明
  | 更新声明
}

DESCRIBE EXPLAIN 语句是同义词。 实际上, DESCRIBE 关键字更常用于获取有关表结构的信息,而 EXPLAIN 用于获取查询执行计划(即,MySQL将如何执行查询的说明)。

以下讨论 根据这些用途使用 DESCRIBE EXPLAIN 关键字,但MySQL解析器将它们视为完全同义。

获取表结构信息

DESCRIBE 提供有关表中列的信息:

MySQL的> DESCRIBE City;
+ ------------ + ---------- + ------ + ------ + --------- +  - -------------- +
| 领域| 输入| 空| 钥匙| 默认| 额外的|
+ ------------ + ---------- + ------ + ------ + --------- +  - -------------- +
| Id | int(11)| 没有| PRI | NULL | auto_increment |
| 名称| char(35)| 没有| | | |
| 国家| char(3)| 没有| UNI | | |
| 区| char(20)| 是的| MUL | | |
| 人口| int(11)| 没有| | 0 | |
+ ------------ + ---------- + ------ + ------ + --------- +  - -------------- +

DESCRIBE 是一个快捷方式 SHOW COLUMNS 这些语句还显示视图的信息。 描述 SHOW COLUMNS 提供了有关输出列的更多信息。 请参见 第13.7.6.5节“显示列语法”

默认情况下, DESCRIBE 显示有关表中所有列的信息。 col_name ,如果给定,则是表中列的名称。 在这种情况下,该语句仅显示指定列的信息。 wild 如果给定,则是一个模式字符串。 它可以包含SQL % _ 通配符。 在这种情况下,语句仅显示名称与字符串匹配的列的输出。 除非字符串包含空格或其他特殊字符,否则无需将字符串括在引号内。

DESCRIBE 提供 声明是为了与Oracle兼容。

SHOW CREATE TABLE SHOW TABLE STATUS SHOW INDEX 语句还提供有关表的信息。 请参见 第13.7.6节“显示语法”

获取执行计划信息

EXPLAIN 语句提供有关MySQL如何执行语句的信息:

EXPLAIN 要求 SELECT 访问的任何表或视图 权限,包括任何基础视图表。 对于视图, EXPLAIN 还需要 SHOW VIEW 特权。

借助于 EXPLAIN ,您可以看到应该向表添加索引的位置,以便通过使用索引查找行来更快地执行语句。 您还可以使用 EXPLAIN 检查优化程序是否以最佳顺序连接表。 要给优化器提供一个提示,以使用与 SELECT 语句 中命名表的顺序相对应的连接顺序 ,请使用 SELECT STRAIGHT_JOIN 而不是仅仅 开始语句 SELECT (参见 第13.2.10节“SELECT语法” 。)

优化器跟踪有时可以提供与其相辅相成的信息 EXPLAIN 但是,优化程序跟踪格式和内容可能会在不同版本之间发生变化。 有关详细信息,请参阅 MySQL内部:跟踪优化程序

如果您在认为应该使用索引时遇到问题,请运行 ANALYZE TABLE 以更新表统计信息,例如密钥的基数,这可能会影响优化程序所做的选择。 请参见 第13.7.3.1节“ANALYZE TABLE语法”

注意

MySQL Workbench具有Visual Explain功能,可以直观地显示 EXPLAIN 输出。 请参阅 教程:使用说明来提高查询性能

13.8.3 HELP语法

帮助' search_string'

HELP 语句返回MySQL参考手册中的在线信息。 正确的操作要求 mysql 使用帮助主题信息初始化数据库 中的帮助表 (请参见 第5.1.14节“服务器端帮助支持” )。

HELP 语句在帮助表中搜索给定的搜索字符串并显示搜索结果。 搜索字符串不区分大小写。

搜索字符串可以包含通配符 % _ 这些与操作员执行的模式匹配操作具有相同的含义 LIKE 例如, HELP 'rep%' 返回以 rep 开头的主题列表

HELP语句了解几种类型的搜索字符串:

  • 在最一般的级别,用于 contents 检索顶级帮助类别的列表:

    帮助'内容'
    
  • 有关给定帮助类别中的主题列表,例如 Data Types ,请使用类别名称:

    帮助'数据类型'
    
  • 有关特定帮助主题(例如 ASCII() 函数或 CREATE TABLE 语句)的帮助,请使用关联的关键字或关键字:

    帮助'ascii'
    帮助'创建表'
    

换句话说,搜索字符串匹配类别,许多主题或单个主题。 您无法事先告知给定的搜索字符串是返回单个帮助主题的项目列表还是帮助信息。 但是,您可以 HELP 通过检查结果集中的行数和列数来确定返回 的响应类型

以下描述指示结果集可以采用的表单。 使用 您在使用 mysql 客户端 时看到 的熟悉的 表格 垂直 格式 显示示例语句的输出 ,但请注意, mysql 本身 以不同的方式 重新格式化 结果集。 HELP

  • 空结果集

    找不到匹配的搜索字符串。

  • 结果集包含一行有三列

    这意味着搜索字符串对帮助主题产生了影响。 结果有三列:

    • name :主题名称。

    • description :主题的描述性帮助文本。

    • example :用法示例或示例。 此列可能为空。

    例: HELP 'replace'

    产量:

    名称:REPLACE
    description:语法:
    REPLACE(STR,from_str均被,to_str)
    
    返回字符串str,其中出现字符串from_str
    替换为字符串to_str。REPLACE()执行区分大小写
    搜索from_str时匹配。
    例如:mysql> SELECT REPLACE('www.mysql.com','w','Ww');
            - >'WwWwWw.mysql.com'
    
  • 结果集包含多行,包含两列

    这意味着搜索字符串匹配了许多帮助主题。 结果集指示帮助主题名称:

    • name :帮助主题名称。

    • is_it_category Y 如果名称代表帮助类别, N 如果不是。 如果不是,则 name 指定为 HELP 语句 参数 应生成包含命名项描述的单行结果集。

    例: HELP 'status'

    产量:

    + ----------------------- + ---------------- +
    | 名字| is_it_category |
    + ----------------------- + ---------------- +
    | 显示| N |
    | SHOW ENGINE | N |
    | 显示主要状态| N |
    | 显示程序状态| N |
    | SHOW SLAVE STATUS | N |
    | 显示状态| N |
    | 显示表状态| N |
    + ----------------------- + ---------------- +
    
  • 结果集包含多行,包含三列

    这意味着搜索字符串与类别匹配。 结果集包含类别条目:

    • source_category_name :帮助类别名称。

    • name :类别或主题名称

    • is_it_category Y 如果名称代表帮助类别, N 如果不是。 如果不是,则 name 指定为 HELP 语句 参数 应生成包含命名项描述的单行结果集。

    例: HELP 'functions'

    产量:

    + ---------------------- + ------------------------- + ---------------- +
    | source_category_name | 名字| is_it_category |
    + ---------------------- + ------------------------- + ---------------- +
    | 功能| 创造功能| N |
    | 功能| 降功能| N |
    | 功能| 位功能| Y |
    | 功能| 比较运算符| Y |
    | 功能| 控制流程功能| Y |
    | 功能| 日期和时间函数| Y |
    | 功能| 加密功能| Y |
    | 功能| 信息功能| Y |
    | 功能| 逻辑运算符| Y |
    | 功能| 杂项功能| Y |
    | 功能| 数字函数| Y |
    | 功能| 字符串函数| Y |
    + ---------------------- + ------------------------- + ---------------- +
    

13.8.4 USE语法

使用 db_name

语句告诉MySQL使用 数据库作为后续语句的默认(当前)数据库。 在会话结束或 发出 另一个 语句 之前,数据库仍然是默认值 USE db_name db_name USE

使用db1;
SELECT COUNT(*)FROM mytable; #从db1.mytable中选择
使用db2;
SELECT COUNT(*)FROM mytable; #从db2.mytable中选择

必须在一行中指定数据库名称。 不支持数据库名称中的换行符。

通过 USE 语句 使特定数据库成为缺省值 不会妨碍访问其他数据库中的表。 以下示例 author db1 数据库和数据库中的 editor 访问该 db2

使用db1;
SELECT author_name,editor_name FROM author,db2.editor
  WHERE author.editor_id = db2.editor.editor_id;

原文