8.4 中文镜像

MySQL 8.4 参考手册 · 中文镜像

正文为中文,英文原文默认隐藏。点击任意中文段落即可展开 / 收起对应英文原文。

打开官方英文原文 ↗

译文由机器翻译生成,仅供理解参考;有疑问请以官方英文原文为准。

中文点击中文段落可显示 / 隐藏英文原文本页译文覆盖 100%

14.19.4 功能依赖的检测14.19.4 Detection of Functional Dependence

以下讨论提供了几个 MySQL 检测函数依赖关系的方法示例。示例使用以下符号:The following discussion provides several examples of the ways in which MySQL detects functional dependencies. The examples use this notation:

{X} -> {Y}

理解这句话为“X 唯一决定 Y,” 这也意味着 Y 在功能上依赖于 X。Understand this as “X uniquely determines Y,” which also means that Y is functionally dependent on X.

示例使用的是 world 数据库,可以从 https://dev.mysql.com/doc/index-other.html 下载。您可以在同一页面找到有关如何安装数据库的详细信息。The examples use the world database, which can be downloaded from https://dev.mysql.com/doc/index-other.html. You can find details on how to install the database on the same page.

由键导出的函数依赖Functional Dependencies Derived from Keys

以下查询选取每个国家的语言数量:The following query selects, for each country, a count of spoken languages:

SELECT co.Name, COUNT(*)
FROM countrylanguage cl, country co
WHERE cl.CountryCode = co.Code
GROUP BY co.Code;

co.Code 是 co 的主键,因此 co 的所有列都函数依赖于它,用这种符号表示:co.Code is a primary key of co, so all columns of co are functionally dependent on it, as expressed using this notation:

{co.Code} -> {co.*}

因此,co.name 函数依赖于 GROUP BY 列,并且该查询是有效的。Thus, co.name is functionally dependent on GROUP BY columns and the query is valid.

可以使用在 UNIQUE 列上的 UNIQUE 索引代替主键,并且相同的函数依赖仍然适用。(对于允许 NULL 值的 NOT NULL 索引,这不成立,因为它允许多个 NULL 值,这种情况下唯一性会丧失。)A UNIQUE index over a NOT NULL column could be used instead of a primary key and the same functional dependence would apply. (This is not true for a UNIQUE index that permits NULL values because it permits multiple NULL values and in that case uniqueness is lost.)

从多列键和等式导出的函数依赖Functional Dependencies Derived from Multiple-Column Keys and from Equalities

该查询为每个国家选择所有使用的语言及讲这些语言的人数列表:This query selects, for each country, a list of all spoken languages and how many people speak them:

SELECT co.Name, cl.Language,
cl.Percentage * co.Population / 100.0 AS SpokenBy
FROM countrylanguage cl, country co
WHERE cl.CountryCode = co.Code
GROUP BY cl.CountryCode, cl.Language;

这一对(cl.CountryCode, cl.Language) 是 cl 的两列复合主键,因此这一列对唯一地确定 cl 的所有列:The pair (cl.CountryCode, cl.Language) is a two-column composite primary key of cl, so that column pair uniquely determines all columns of cl:

{cl.CountryCode, cl.Language} -> {cl.*}

此外,由于 WHERE 子句中的等式:Moreover, because of the equality in the WHERE clause:

{cl.CountryCode} -> {co.Code}

并且,因为 co.Code 是 co 的主键:And, because co.Code is primary key of co:

{co.Code} -> {co.*}

“唯一确定” 关系是可传递的,因此:“Uniquely determines” relationships are transitive, therefore:

{cl.CountryCode, cl.Language} -> {cl.*,co.*}

因此,该查询是有效的。As a result, the query is valid.

与前面的例子一样,可以在 NOT NULL 列上使用 UNIQUE 键代替主键。As with the previous example, a UNIQUE key over NOT NULL columns could be used instead of a primary key.

可以使用 INNER JOIN 条件代替 WHERE。相同的函数依赖性适用:An INNER JOIN condition can be used instead of WHERE. The same functional dependencies apply:

SELECT co.Name, cl.Language,
cl.Percentage * co.Population/100.0 AS SpokenBy
FROM countrylanguage cl INNER JOIN country co
ON cl.CountryCode = co.Code
GROUP BY cl.CountryCode, cl.Language;

函数依赖特殊情况Functional Dependency Special Cases

虽然 WHERE 条件或 INNER JOIN 条件中的相等测试是对称的,但外连接条件中的相等测试不是对称的,因为表扮演的角色不同。Whereas an equality test in a WHERE condition or INNER JOIN condition is symmetric, an equality test in an outer join condition is not, because tables play different roles.

假设参照完整性意外被破坏,并且存在一行 countrylanguage 数据而在 country 中没有对应行。考虑与前一个示例相同的查询,但使用 LEFT JOIN:Assume that referential integrity has been accidentally broken and there exists a row of countrylanguage without a corresponding row in country. Consider the same query as in the previous example, but with a LEFT JOIN:

SELECT co.Name, cl.Language,
cl.Percentage * co.Population/100.0 AS SpokenBy
FROM countrylanguage cl LEFT JOIN country co
ON cl.CountryCode = co.Code
GROUP BY cl.CountryCode, cl.Language;

对于给定的 cl.CountryCode 值,连接结果中的 co.Code 值要么在匹配的行中找到(由 cl.CountryCode 决定),要么在没有匹配的情况下被 NULL 补充(同样由 cl.CountryCode 决定)。在每种情况下,这种关系适用:For a given value of cl.CountryCode, the value of co.Code in the join result is either found in a matching row (determined by cl.CountryCode) or is NULL-complemented if there is no match (also determined by cl.CountryCode). In each case, this relationship applies:

{cl.CountryCode} -> {co.Code}

cl.CountryCode 本身函数依赖于 {cl.CountryCode, cl.Language},这是一个主键。cl.CountryCode is itself functionally dependent on {cl.CountryCode, cl.Language} which is a primary key.

如果在连接结果中 co.Code 被 NULL 补全,则 co.Name 也会被补全。如果 co.Code 没有被 NULL 补全,那么由于 co.Code 是主键,它决定了 co.Name。因此,在所有情况下:If in the join result co.Code is NULL-complemented, co.Name is as well. If co.Code is not NULL-complemented, then because co.Code is a primary key, it determines co.Name. Therefore, in all cases:

{co.Code} -> {co.Name}

结果如下:Which yields:

{cl.CountryCode, cl.Language} -> {cl.*,co.*}

因此,该查询是有效的。As a result, the query is valid.

但是,假设表格被交换,如在此查询中:However, suppose that the tables are swapped, as in this query:

SELECT co.Name, cl.Language,
cl.Percentage * co.Population/100.0 AS SpokenBy
FROM country co LEFT JOIN countrylanguage cl
ON cl.CountryCode = co.Code
GROUP BY cl.CountryCode, cl.Language;

现在这种关系 不适用:Now this relationship does not apply:

{cl.CountryCode, cl.Language} -> {cl.*,co.*}

实际上,为 cl 创建的所有 NULL 补充行都被放入单个组中(它们的 GROUP BY 列都等于 NULL),并且在该组内 co.Name 的值可以变化。查询无效,MySQL 会拒绝它。Indeed, all NULL-complemented rows made for cl is put into a single group (they have both GROUP BY columns equal to NULL), and inside this group the value of co.Name can vary. The query is invalid and MySQL rejects it.

因此,外连接中的函数依赖性与决定列是否属于 LEFT JOIN 的左侧或右侧相关。如果存在嵌套的外连接或连接条件不完全是等值比较,则函数依赖性的确定会更加复杂。Functional dependence in outer joins is thus linked to whether determinant columns belong to the left or right side of the LEFT JOIN. Determination of functional dependence becomes more complex if there are nested outer joins or the join condition does not consist entirely of equality comparisons.

函数依赖与视图Functional Dependencies and Views

假设一个关于国家的视图会生成它们的代码、它们的大写名称以及它们有多少种不同的官方语言:Suppose that a view on countries produces their code, their name in uppercase, and how many different official languages they have:

CREATE VIEW country2 AS
SELECT co.Code, UPPER(co.Name) AS UpperName,
COUNT(cl.Language) AS OfficialLanguages
FROM country AS co JOIN countrylanguage AS cl
ON cl.CountryCode = co.Code
WHERE cl.isOfficial = 'T'
GROUP BY co.Code;

这个定义是有效的,因为:This definition is valid because:

{co.Code} -> {co.*}

在视图结果中,第一个选中的列是 co.Code,它也是分组列,因此决定了所有其他选中的表达式:In the view result, the first selected column is co.Code, which is also the group column and thus determines all other selected expressions:

{country2.Code} -> {country2.*}

MySQL 理解这一点,并按照以下描述使用这些信息。MySQL understands this and uses this information, as described following.

此查询显示各个国家的官方语言数量以及城市数量,通过将视图与 city 表连接实现:This query displays countries, how many different official languages they have, and how many cities they have, by joining the view with the city table:

SELECT co2.Code, co2.UpperName, co2.OfficialLanguages,
COUNT(*) AS Cities
FROM country2 AS co2 JOIN city ci
ON ci.CountryCode = co2.Code
GROUP BY co2.Code;

这个查询是有效的,因为,如前所见:This query is valid because, as seen previously:

{co2.Code} -> {co2.*}

MySQL 能够在视图的结果中发现一个函数依赖,并利用该依赖来验证使用该视图的查询。如果 country2 是一个派生表(或公共表表达式),情况也是一样,如下所示:MySQL is able to discover a functional dependency in the result of a view and use that to validate a query which uses the view. The same would be true if country2 were a derived table (or common table expression), as in:

SELECT co2.Code, co2.UpperName, co2.OfficialLanguages,
COUNT(*) AS Cities
FROM
(
 SELECT co.Code, UPPER(co.Name) AS UpperName,
 COUNT(cl.Language) AS OfficialLanguages
 FROM country AS co JOIN countrylanguage AS cl
 ON cl.CountryCode=co.Code
 WHERE cl.isOfficial='T'
 GROUP BY co.Code
) AS co2
JOIN city ci ON ci.CountryCode = co2.Code
GROUP BY co2.Code;

函数依赖的组合Combinations of Functional Dependencies

MySQL 能够结合前述所有类型的函数依赖(基于键、基于等式、基于视图)来验证更复杂的查询。MySQL is able to combine all of the preceding types of functional dependencies (key based, equality based, view based) to validate more complex queries.