主键的 mariadb 优化不起作用
mariadb optimisation of primary key not working
如果您在非空列上使用计数,在一个 table 上,没有任何 where-parts,优化器只是 return table 中的行数].
如果您要求对 UNIQE 非空列(如 PRIMARY KEY)进行 DISTINCT 计数,答案应该相同,但这次 mariadb 会执行计算。
并且如果您在其他 table 上左连接,但仍然没有 where-parts,结果应该仍然是 table.
中的行数
mariadb 不使用thous 优化有什么原因吗?是否存在未过滤的主键的 DISTINCT 计数可以给出除该表中的行数之外的任何其他结果的情况?
案例:
CREATE TABLE products (
our_article_id varchar(50) CHARACTER SET utf8 NOT NULL,
...,
PRIMARY KEY(our_article_id)
);
CREATE TABLE product_article_id (
article_id varchar(255) COLLATE utf8_bin NOT NULL,
our_article_id varchar(50) CHARACTER SET utf8 NOT NULL,
...
PRIMARY KEY(article_id),
INDEX(our_article_id)
);
计数查询,第 1 次,基本计数
DESCRIBE SELECT COUNT(our_article_id) FROM products;
+------+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+------+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
主键上的第 2 个 DISTINCT
DESCRIBE SELECT COUNT(DISTINCT our_article_id) FROM products;
+------+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+
| 1 | SIMPLE | products | index | NULL | PRIMARY | 152 | NULL | 225089 | Using index |
+------+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+
3,主键上的 DISTINCT,以及没有 WHERE 部分的 LEFT JOIN
DESCRIBE SELECT COUNT(DISTINCT our_article_id) FROM products LEFT JOIN product_article_id USING (our_article_id);
+------+-------------+--------------------+-------+---------------+---------+---------+----------------------------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+--------------------+-------+---------------+---------+---------+----------------------------------+--------+-------------+
| 1 | SIMPLE | products | index | NULL | PRIMARY | 152 | NULL | 225089 | Using index |
| 1 | SIMPLE | product_article_id | ref | PRIMARY | PRIMARY | 152 | testseek.products.our_article_id | 12579 | Using index |
+------+-------------+--------------------+-------+---------------+---------+---------+----------------------------------+--------+-------------+
"Is there a reason for mariadb not using thous optimizations?" -- MySQL/MariaDB 中缺少无数优化;那不见了。让我们看看历史。
MySQL 大约 2 年前开始作为一个精简而平均的数据库引擎。它专注于大多数人需要的功能,同时最大限度地减少开销。这意味着早期版本中没有很多罕见的优化,只有当它们看起来足够重要时才会随着时间的推移而添加。
以PRIMARY KEY
为例。它被定义为唯一的。它是由 BTree 组织的。并且,对于 InnoDB,它也被定义为 Clustered。其他供应商允许各种组合集群、非 BTree 索引等。MySQL 决定对 "most" 人的限制是 "good enough"。
这些年来,'worst' 遗漏的部分已逐步修复。交易可能是最大和最重要的。它于 2001 年(?)到达,随着 8.0 的出现,MyISAM 在今年(2016 年)被删除。
4.1 (2002?) 看到了子查询。在此之前,创建 tmp table 是 "good enough"。现在 (8.0) 子查询正在被 CTE 提升,它涵盖了 tmp tables 和子查询都无法有效完成的一些事情。
MySQL 5.6 和 5.7 以及 MariaDB 10.x 进行了大量优化;您可能只使用过其中的几个。产品进入 "diminishing returns"。如果它放慢优化程序以检查接下来的一千个极其罕见的优化,它会损坏其 "lean and mean" 传统。
与此同时,像我这样的人会花很多时间说 "MySQL/MariaDB doesn't have that; here's the workaround"。在您的情况下,它是较短的 COUNT(*)
。由于有一个干净的解决方法,可能还需要十年才能实施您的建议。可以使用 bugs.mysql.com 或 mariadb.com 提交错误报告以提出优化建议。
另一个几乎不需要的情况是 INDEX(a ASC, b DESC)
作为优化 ORDER BY a ASC, b DESC
的一种方式。这是 8.0 附带的。但我怀疑 5,000 个查询中是否有超过一个查询真的需要它。 (我看到了很多查询。)我认为它的稀有性是为什么花了 20 年才实现它的原因。缺乏干净的解决方法是它没有再花十年的原因。
如果您在非空列上使用计数,在一个 table 上,没有任何 where-parts,优化器只是 return table 中的行数].
如果您要求对 UNIQE 非空列(如 PRIMARY KEY)进行 DISTINCT 计数,答案应该相同,但这次 mariadb 会执行计算。
并且如果您在其他 table 上左连接,但仍然没有 where-parts,结果应该仍然是 table.
中的行数mariadb 不使用thous 优化有什么原因吗?是否存在未过滤的主键的 DISTINCT 计数可以给出除该表中的行数之外的任何其他结果的情况?
案例:
CREATE TABLE products (
our_article_id varchar(50) CHARACTER SET utf8 NOT NULL,
...,
PRIMARY KEY(our_article_id)
);
CREATE TABLE product_article_id (
article_id varchar(255) COLLATE utf8_bin NOT NULL,
our_article_id varchar(50) CHARACTER SET utf8 NOT NULL,
...
PRIMARY KEY(article_id),
INDEX(our_article_id)
);
计数查询,第 1 次,基本计数
DESCRIBE SELECT COUNT(our_article_id) FROM products;
+------+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+------+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
主键上的第 2 个 DISTINCT
DESCRIBE SELECT COUNT(DISTINCT our_article_id) FROM products;
+------+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+
| 1 | SIMPLE | products | index | NULL | PRIMARY | 152 | NULL | 225089 | Using index |
+------+-------------+----------+-------+---------------+---------+---------+------+--------+-------------+
3,主键上的 DISTINCT,以及没有 WHERE 部分的 LEFT JOIN
DESCRIBE SELECT COUNT(DISTINCT our_article_id) FROM products LEFT JOIN product_article_id USING (our_article_id);
+------+-------------+--------------------+-------+---------------+---------+---------+----------------------------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+--------------------+-------+---------------+---------+---------+----------------------------------+--------+-------------+
| 1 | SIMPLE | products | index | NULL | PRIMARY | 152 | NULL | 225089 | Using index |
| 1 | SIMPLE | product_article_id | ref | PRIMARY | PRIMARY | 152 | testseek.products.our_article_id | 12579 | Using index |
+------+-------------+--------------------+-------+---------------+---------+---------+----------------------------------+--------+-------------+
"Is there a reason for mariadb not using thous optimizations?" -- MySQL/MariaDB 中缺少无数优化;那不见了。让我们看看历史。
MySQL 大约 2 年前开始作为一个精简而平均的数据库引擎。它专注于大多数人需要的功能,同时最大限度地减少开销。这意味着早期版本中没有很多罕见的优化,只有当它们看起来足够重要时才会随着时间的推移而添加。
以PRIMARY KEY
为例。它被定义为唯一的。它是由 BTree 组织的。并且,对于 InnoDB,它也被定义为 Clustered。其他供应商允许各种组合集群、非 BTree 索引等。MySQL 决定对 "most" 人的限制是 "good enough"。
这些年来,'worst' 遗漏的部分已逐步修复。交易可能是最大和最重要的。它于 2001 年(?)到达,随着 8.0 的出现,MyISAM 在今年(2016 年)被删除。
4.1 (2002?) 看到了子查询。在此之前,创建 tmp table 是 "good enough"。现在 (8.0) 子查询正在被 CTE 提升,它涵盖了 tmp tables 和子查询都无法有效完成的一些事情。
MySQL 5.6 和 5.7 以及 MariaDB 10.x 进行了大量优化;您可能只使用过其中的几个。产品进入 "diminishing returns"。如果它放慢优化程序以检查接下来的一千个极其罕见的优化,它会损坏其 "lean and mean" 传统。
与此同时,像我这样的人会花很多时间说 "MySQL/MariaDB doesn't have that; here's the workaround"。在您的情况下,它是较短的 COUNT(*)
。由于有一个干净的解决方法,可能还需要十年才能实施您的建议。可以使用 bugs.mysql.com 或 mariadb.com 提交错误报告以提出优化建议。
另一个几乎不需要的情况是 INDEX(a ASC, b DESC)
作为优化 ORDER BY a ASC, b DESC
的一种方式。这是 8.0 附带的。但我怀疑 5,000 个查询中是否有超过一个查询真的需要它。 (我看到了很多查询。)我认为它的稀有性是为什么花了 20 年才实现它的原因。缺乏干净的解决方法是它没有再花十年的原因。