12.15 信息功能

table12.19 信息功能

NameDescription
BENCHMARK()重复执行一个 table 达式
CHARSET()返回参数的字符集
COERCIBILITY()返回字符串参数的排序规则强制性值
COLLATION()返回字符串参数的排序规则
CONNECTION_ID()返回连接的连接 ID(线程 ID)
CURRENT_USER(), CURRENT_USER经过身份验证的用户名和主机名
DATABASE()返回默认(当前)数据库名称
FOUND_ROWS()对于带有 LIMIT 子句的 SELECT,如果没有 LIMIT 子句,则将返回的行数
LAST_INSERT_ID()最后一个 INSERT 的 AUTOINCREMENT 列的值
ROW_COUNT()更新的行数
SCHEMA()DATABASE()的同义词
SESSION_USER()USER()的同义词
SYSTEM_USER()USER()的同义词
USER()Client 端提供的用户名和主机名
VERSION()返回指示 MySQL 服务器版本的字符串

BENCHMARK(count,expr)

BENCHMARK()函数重复执行* expr * * count *次。它可以用来计时 MySQL 处理 table 达式的速度。结果值是0,对于不适当的参数(例如NULL或负重复计数)为NULL

预期用途来自mysqlClient 端,该 Client 端报告查询执行时间:

mysql> SELECT BENCHMARK(1000000,AES_ENCRYPT('hello','goodbye'));
+---------------------------------------------------+
| BENCHMARK(1000000,AES_ENCRYPT('hello','goodbye')) |
+---------------------------------------------------+
|                                                 0 |
+---------------------------------------------------+
1 row in set (4.74 sec)

报告的时间是 Client 端的经过时间,而不是服务器端的 CPU 时间。建议执行BENCHMARK()次,并解释有关服务器计算机负载的结果。

BENCHMARK()用于测量标量 table 达式的运行时性能,这对使用它和解释结果的方式有一些重要影响:

  • 只能使用标量 table 达式。尽管 table 达式可以是子查询,但它必须返回单列和最多单行。例如,如果 tablet具有多于一列或多于一行,则基准(10,(SELECT * FROM t))将失败。

    • 在涉及的开销方面,执行SELECT expr语句* N 的时间与执行SELECT BENCHMARK(N, expr)的时间不同。两者的执行配置文件非常不同,您不应期望它们花费相同的时间。前者涉及解析器,优化器,table 锁定和运行时评估 N 每次。后者仅涉及运行时评估 N *次,而所有其他组件仅评估一次。已经分配的内存结构将被重用,并且运行时优化(例如已针对聚合函数评估的结果的本地缓存)可能会更改结果。 BENCHMARK()的使用因此通过赋予该组件更多的权重并消除网络,解析器,优化器等引入的“噪音”来衡量该组件的性能。

CHARSET(str)

返回字符串参数的字符集。

mysql> SELECT CHARSET('abc');
        -> 'latin1'
mysql> SELECT CHARSET(CONVERT('abc' USING utf8));
        -> 'utf8'
mysql> SELECT CHARSET(USER());
        -> 'utf8'

COERCIBILITY(str)

返回字符串参数的排序规则强制性值。

mysql> SELECT COERCIBILITY('abc' COLLATE latin1_swedish_ci);
        -> 0
mysql> SELECT COERCIBILITY(USER());
        -> 3
mysql> SELECT COERCIBILITY('abc');
        -> 4
mysql> SELECT COERCIBILITY(1000);
        -> 5

返回值的含义如下 table 所示。较低的值具有较高的优先级。

CoercibilityMeaningExample
0Explicit collation带有COLLATE子句的值
1No collation具有不同排序规则的字符串的串联
2Implicit collation列值,存储的例程参数或局部变量
3System constantUSER()返回值
4CoercibleLiteral string
5Numeric数值或时间值
5IgnorableNULL或源自NULL的 table 达式

有关更多信息,请参见第 10.8.4 节“table 达式中的排序规则强制性”

COLLATION(str)

返回字符串参数的排序规则。

mysql> SELECT COLLATION('abc');
        -> 'latin1_swedish_ci'
mysql> SELECT COLLATION(_utf8'abc');
        -> 'utf8_general_ci'

CONNECTION_ID()

返回连接的连接 ID(线程 ID)。每个连接都有一个在当前连接的 Client 端集中唯一的 ID。

CONNECTION_ID()返回的值与INFORMATION_SCHEMA.PROCESSLISTtable 的ID列,SHOW PROCESSLIST输出的Id列和 Performance Schema threadstable 的PROCESSLIST_ID列中显示的值类型相同。

mysql> SELECT CONNECTION_ID();
        -> 23786

CURRENT_USER, CURRENT_USER()

返回服务器用来认证当前 Client 端的 MySQL 帐户的用户名和主机名组合。该帐户确定您的访问权限。返回值是utf8字符集中的字符串。

CURRENT_USER()的值可以与USER()的值不同。

mysql> SELECT USER();
        -> 'davida@localhost'
mysql> SELECT * FROM mysql.user;
ERROR 1044: Access denied for user ''@'localhost' to
database 'mysql'
mysql> SELECT CURRENT_USER();
        -> '@localhost'

该示例说明,尽管 Client 端指定了davida的用户名(如USER()函数的值所示),但服务器仍使用匿名用户帐户对 Client 端进行了身份验证(如CURRENT_USER()值的空用户名部分所示)。发生这种情况的一种方法是,在davida的授予 table 中没有列出帐户。

在存储的程序或视图中,CURRENT_USER()返回定义对象的用户的帐户(由其DEFINER值给出),除非使用SQL SECURITY INVOKER特性定义。在后一种情况下,CURRENT_USER()返回对象的调用者。

触发器和事件没有定义SQL SECURITY特性的选项,因此对于这些对象,CURRENT_USER()返回定义该对象的用户的帐户。要返回调用者,请使用USER()SESSION_USER()

以下语句支持使用CURRENT_USER()函数代替受影响的用户或定义者的名称(并可能是其主机)。在这种情况下,CURRENT_USER()将在需要的位置和位置扩展:

有关CURRENT_USER()的扩展对复制的影响的信息,请参见第 16.4.1.8 节“ CURRENT_USER()的复制”

DATABASE()

utf8字符集的字符串形式返回默认(当前)数据库名称。如果没有默认数据库,则DATABASE()返回NULL。在存储的例程中,默认数据库是与该例程关联的数据库,它不一定与调用上下文中的默认数据库相同。

mysql> SELECT DATABASE();
        -> 'test'

如果没有默认数据库,则DATABASE()返回NULL

FOUND_ROWS()

SELECT语句可以包含LIMIT子句以限制服务器返回给 Client 端的行数。在某些情况下,希望知道该语句在没有LIMIT的情况下将返回多少行,而无需再次运行该语句。要获得此行计数,请在SELECT语句中包含SQL_CALC_FOUND_ROWS选项,然后再调用FOUND_ROWS()

mysql> SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name
    -> WHERE id > 100 LIMIT 10;
mysql> SELECT FOUND_ROWS();

第二个SELECT返回一个数字,该数字指示如果不使用LIMIT子句写入第一个SELECT将会返回多少行。

在最近成功执行的SELECT语句中没有SQL_CALC_FOUND_ROWS选项的情况下,FOUND_ROWS()返回该语句返回的结果集中的行数。如果该语句包含LIMIT子句,则FOUND_ROWS()返回不超过限制的行数。例如,如果语句包含LIMIT 10LIMIT 50, 10,则FOUND_ROWS()分别返回 10 或 60.

通过FOUND_ROWS()可用的行计数是临时的,并且在SELECT SQL_CALC_FOUND_ROWS语句之后的语句之后不可用。如果以后需要引用该值,请保存它:

mysql> SELECT SQL_CALC_FOUND_ROWS * FROM ... ;
mysql> SET @rows = FOUND_ROWS();

如果您使用的是SELECT SQL_CALC_FOUND_ROWS,MySQL 必须计算整个结果集中有多少行。但是,这比不使用LIMIT再次运行查询要快,因为不需要将结果集发送到 Client 端。

SQL_CALC_FOUND_ROWSFOUND_ROWS()在希望限制查询返回的行数但又要确定整个结果集中的行数而又不用再次运行查询的情况下很有用。一个示例是一个 Web 脚本,它显示一个页面显示,其中包含指向显示搜索结果其他部分的页面的链接。使用FOUND_ROWS(),您可以确定结果的其余部分还需要多少其他页面。

UNION语句的使用SQL_CALC_FOUND_ROWSFOUND_ROWS()比简单SELECT语句的使用更为复杂,因为LIMIT可能出现在UNION的多个位置。它可以应用于UNION中的单个SELECT语句,也可以应用于整个UNION结果。

SQL_CALC_FOUND_ROWS对于UNION的意图是,它应返回没有全局LIMIT时将返回的行数。将SQL_CALC_FOUND_ROWSUNION一起使用的条件是:

  • SQL_CALC_FOUND_ROWS关键字必须出现在UNION的前SELECT中。

    • 仅当使用UNION ALL时,FOUND_ROWS()的值才是正确的。如果使用UNION而不使用ALL,则会发生重复删除,并且FOUND_ROWS()的值仅是近似值。

    • 如果UNION中不存在LIMIT,则SQL_CALC_FOUND_ROWS将被忽略并返回在临时 table 中创建的用于处理UNION的行数。

除了此处描述的情况外,FOUND_ROWS()的行为是不确定的(例如,在SELECT语句后由于错误而失败的值)。

Important

使用基于语句的复制无法可靠地复制FOUND_ROWS()。使用基于行的复制会自动复制此功能。

LAST_INSERT_ID(), LAST_INSERT_ID(expr)

不带任何参数的LAST_INSERT_ID()返回BIGINT UNSIGNED(64 位)值,该值 table 示由于最近执行的INSERT语句而成功为AUTO_INCREMENT列成功插入的第一个自动生成的值。如果没有成功插入行,则LAST_INSERT_ID()的值保持不变。

带有一个参数的LAST_INSERT_ID()返回无符号整数。

例如,在插入生成AUTO_INCREMENT值的行之后,您可以像这样获得该值:

mysql> SELECT LAST_INSERT_ID();
        -> 195

当前正在执行的语句不会影响LAST_INSERT_ID()的值。假设您使用一个语句生成了一个AUTO_INCREMENT值,然后在多行INSERT语句中引用了LAST_INSERT_ID(),该语句将行插入具有自己的AUTO_INCREMENT列的 table 中。 LAST_INSERT_ID()的值将在第二条语句中保持稳定;第二行和第二行的值不受较早行插入的影响。 (但是,如果混合使用对LAST_INSERT_ID()LAST_INSERT_ID(expr)的引用,则效果是不确定的。)

如果前一条语句返回错误,则LAST_INSERT_ID()的值不确定。对于事务 table,如果由于错误而回滚该语句,则LAST_INSERT_ID()的值将保持未定义状态。对于手册ROLLBACKLAST_INSERT_ID()的值不会恢复为 Transaction 之前的值;它保持在ROLLBACK的位置。

在存储的例程(过程或函数)或触发器的主体内,LAST_INSERT_ID()的值的更改方式与在此类对象的主体外部执行的语句的更改方式相同。以下语句所看到的存储例程或触发器对LAST_INSERT_ID()值的影响取决于例程的类型:

  • 如果存储过程执行的语句更改了LAST_INSERT_ID()的值,则该过程调用后的语句将看到更改的值。

    • 对于存储的函数和更改该值的触发器,该函数或触发器结束时将恢复该值,因此以下语句将看不到更改后的值。

生成的 ID 以每个连接的形式保存在服务器中。这意味着函数返回给定 Client 端的值是为该 Client 端*影响AUTO_INCREMENT列的最新语句生成的第一个AUTO_INCREMENT值。即使其他 Client 端生成自己的AUTO_INCREMENT值,该值也不会受到其他 Client 端的影响。此行为可确保每个 Client 端都可以检索自己的 ID,而不必担心其他 Client 端的活动,也不需要锁或事务。

如果将行的AUTO_INCREMENT列设置为非“ magic”值(即,不是NULL也不是0的值),则LAST_INSERT_ID()的值不会更改。

Important

如果使用单个INSERT语句插入多行,则LAST_INSERT_ID()返回为* first 插入的行 only *生成的值。这样做的原因是使针对其他服务器轻松再现相同的INSERT语句成为可能。

For example:

mysql> USE test;

mysql> CREATE TABLE t (
       id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
       name VARCHAR(10) NOT NULL
       );

mysql> INSERT INTO t VALUES (NULL, 'Bob');

mysql> SELECT * FROM t;
+----+------+
| id | name |
+----+------+
|  1 | Bob  |
+----+------+

mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                1 |
+------------------+

mysql> INSERT INTO t VALUES
       (NULL, 'Mary'), (NULL, 'Jane'), (NULL, 'Lisa');

mysql> SELECT * FROM t;
+----+------+
| id | name |
+----+------+
|  1 | Bob  |
|  2 | Mary |
|  3 | Jane |
|  4 | Lisa |
+----+------+

mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                2 |
+------------------+

尽管第二个INSERT语句在t中插入了三个新行,但是为这些行中的第一行生成的 ID 是2,并且此值由LAST_INSERT_ID()返回给随后的SELECT语句。

如果使用INSERT IGNORE并且忽略该行,则LAST_INSERT_ID()将从当前值保持不变(如果连接尚未成功执行INSERT,则返回 0),并且对于非事务处理 table,AUTO_INCREMENT计数器不会递增。对于InnoDBtable,如果innodb_autoinc_lock_mode设置为12,则AUTO_INCREMENT计数器增加,如以下示例所示:

mysql> USE test;

mysql> SELECT @@innodb_autoinc_lock_mode;
+----------------------------+
| @@innodb_autoinc_lock_mode |
+----------------------------+
|                          1 |
+----------------------------+

mysql> CREATE TABLE `t` (
       `id` INT(11) NOT NULL AUTO_INCREMENT,
       `val` INT(11) DEFAULT NULL,
       PRIMARY KEY (`id`),
       UNIQUE KEY `i1` (`val`)
       ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

# Insert two rows

mysql> INSERT INTO t (val) VALUES (1),(2);

# With auto_increment_offset=1, the inserted rows
# result in an AUTO_INCREMENT value of 3

mysql> SHOW CREATE TABLE t\G
*************************** 1. row ***************************
       Table: t
Create Table: CREATE TABLE `t` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `val` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `i1` (`val`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1

# LAST_INSERT_ID() returns the first automatically generated
# value that is successfully inserted for the AUTO_INCREMENT column

mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                1 |
+------------------+

# The attempted insertion of duplicate rows fail but errors are ignored

mysql> INSERT IGNORE INTO t (val) VALUES (1),(2);
Query OK, 0 rows affected (0.00 sec)
Records: 2  Duplicates: 2  Warnings: 0

# With innodb_autoinc_lock_mode=1, the AUTO_INCREMENT counter
# is incremented for the ignored rows

mysql> SHOW CREATE TABLE t\G
*************************** 1. row ***************************
       Table: t
Create Table: CREATE TABLE `t` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `val` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `i1` (`val`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1

# The LAST_INSERT_ID is unchanged because the previous insert was unsuccessful

mysql> SELECT LAST_INSERT_ID();
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                1 |
+------------------+

有关更多信息,请参见第 14.6.1.6 节“ InnoDB 中的 AUTO_INCREMENT 处理”

如果将* expr *作为LAST_INSERT_ID()的参数给出,则该参数的值由函数返回,并记为LAST_INSERT_ID()返回的下一个值。这可以用来模拟序列:

  • 创建一个 table 来保存序列计数器并对其进行初始化:
mysql> CREATE TABLE sequence (id INT NOT NULL);
mysql> INSERT INTO sequence VALUES (0);
  • 使用该 table 生成如下的序列号:
mysql> UPDATE sequence SET id=LAST_INSERT_ID(id+1);
mysql> SELECT LAST_INSERT_ID();

UPDATE语句递增序列计数器,并导致对LAST_INSERT_ID()的下一次调用返回更新后的值。 SELECT语句检索该值。 mysql_insert_id() C API 函数也可以用于获取值。参见第 27.7.6.38 节“ mysql_insert_id()”

您可以生成序列而无需调用LAST_INSERT_ID(),但是以这种方式使用该函数的实用工具是将 ID 值作为最后一个自动生成的值保留在服务器中。这是多用户安全的,因为多个 Client 端可以发出UPDATE语句并通过SELECT语句(或mysql_insert_id())获得自己的序列值,而不会影响或受到生成自己序列值的其他 Client 端的影响。

请注意,mysql_insert_id()仅在INSERTUPDATE语句之后更新,因此在执行SELECTSET之类的其他 SQL 语句之后,不能使用 C API 函数来检索LAST_INSERT_ID(expr)的值。

ROW_COUNT()

ROW_COUNT()返回的值如下:

  • DDL 语句:0.这适用于诸如CREATE TABLEDROP TABLE的语句。

    • SELECT以外的 DML 语句:受影响的行数。这适用于诸如UPDATEINSERTDELETE之类的语句(如前所述),但现在也适用于诸如ALTER TABLELOAD DATA之类的语句。

    • SELECT:如果语句返回结果集,则为-1,否则返回“受影响”的行数。例如,对于SELECT * FROM t1ROW_COUNT()返回-1.对于SELECT * FROM t1 INTO OUTFILE 'file_name'ROW_COUNT()返回写入文件的行数。

    • SIGNAL条语句:0.

对于UPDATE语句,默认情况下受影响的行值为实际更改的行数。如果在连接到mysqld时将CLIENT_FOUND_ROWS标志指定为mysql_real_connect(),则受影响的行值为“找到”的行数;否则,为 0.也就是说,与WHERE子句匹配。

对于REPLACE语句,如果新行替换了旧行,则受影响的行值为 2,因为在这种情况下,删除重复项后将插入一行。

对于插入...在重复的密钥更新上语句,如果将行作为新行插入,则每行的受影响行值为 1;如果更新了现有行,则为 2;如果将现有行设置为其当前值,则为 0.如果指定CLIENT_FOUND_ROWS标志,则将现有行设置为其当前值时,受影响的行值为 1(而不是 0)。

ROW_COUNT()值类似于mysql_affected_rows() C API 函数中的值以及mysqlClient 端在语句执行后显示的行数。

mysql> INSERT INTO t VALUES(1),(2),(3);
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT ROW_COUNT();
+-------------+
| ROW_COUNT() |
+-------------+
|           3 |
+-------------+
1 row in set (0.00 sec)

mysql> DELETE FROM t WHERE i IN(1,2);
Query OK, 2 rows affected (0.00 sec)

mysql> SELECT ROW_COUNT();
+-------------+
| ROW_COUNT() |
+-------------+
|           2 |
+-------------+
1 row in set (0.00 sec)

Important

使用基于语句的复制无法可靠地复制ROW_COUNT()。使用基于行的复制会自动复制此功能。

SCHEMA()

此函数是DATABASE()的同义词。

SESSION_USER()

SESSION_USER()USER()的同义词。

SYSTEM_USER()

SYSTEM_USER()USER()的同义词。

USER()

utf8字符集的字符串形式返回当前 MySQL 用户名和主机名。

mysql> SELECT USER();
        -> 'davida@localhost'

该值指示您在连接到服务器时指定的用户名,以及从中连接的 Client 端主机。该值可以与CURRENT_USER()的值不同。

VERSION()

返回指示 MySQL 服务器版本的字符串。该字符串使用utf8字符集。该值除版本号外还可以带有后缀。请参阅第 5.1.7 节“服务器系统变量”中对version系统变量的描述。

此功能对于基于语句的复制不安全。如果在binlog_format设置为STATEMENT时使用此功能,则会记录一条警告。

mysql> SELECT VERSION();
        -> '5.7.32-standard'