MySQL:基于聚合查询的视图索引

Posted

技术标签:

【中文标题】MySQL:基于聚合查询的视图索引【英文标题】:MySQL : Indexes for View based on an aggregated query 【发布时间】:2019-09-23 15:06:28 【问题描述】:

我有一个工作的、漂亮的、索引的 SQL 查询,它为我的所有用户和其他东西聚合注释(整数总和)。这是“查询 A”。

我想在其他查询中使用此汇总注释,例如“查询 B”。

如果我基于“查询A”创建一个视图,如果我在“查询B”中加入它,是否会在需要时使用原始查询的索引?

mysql 是这样吗?对于其他风格的 SQL?

谢谢。

【问题讨论】:

“索引 SQL 查询”是什么意思?你的意思是它使用像FORCE INDEX这样的选项? 不,只是一个包含多个连接和条件的查询,全部在索引列上。 试试吧。使用EXPLAIN SELECT <<query B>>。一般来说,VIEWs 是语法糖,并没有提供任何其他功能。另外,什么版本的 MySQL? 【参考方案1】:

在 MySQL 中,您不能在视图上创建索引。当您针对使用合并算法的视图查询数据时,MySQL 使用基础表的索引。对于使用 temptable 算法的视图,当您针对视图查询数据时,不会使用索引。

https://www.percona.com/blog/2007/08/12/mysql-view-as-performance-troublemaker/

【讨论】:

所以合并算法会很好,但由于我的查询 A 中的聚合,不能在这里使用。所以我没有索引。那是Mysql特有的吗? 内部视图使用索引来创建聚合。但是您不能在 SELECT * FROM view v JOIN table t ON v.id = t.id 之类的东西上使用索引 所以 Juan Carlos Oropeza 的观点与非常小的数据集相关?【参考方案2】:

这是一个演示表。它有一个userid 属性列和一个note 列。

mysql> 创建表t(id 序列主键, userid int not null, note int, key(userid,note));

如果您进行聚合以获取每个useridnote 的总和,它会对(userid, note) 进行索引扫描。

mysql> explain select userid, sum(note) from t group by userid;
+----+-------------+-------+-------+---------------+--------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key    | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+--------+---------+------+------+-------------+
|  1 | SIMPLE      | t     | index | userid        | userid | 9       | NULL |    1 | Using index |
+----+-------------+-------+-------+---------------+--------+---------+------+------+-------------+
1 row in set (0.00 sec)

如果我们为同一个查询创建一个视图,那么我们可以看到查询该视图使用基础表上的相同索引。 MySQL 中的视图很像宏——它们只是查询基础表。

mysql> create view v as select userid, sum(note) from t group by userid;
Query OK, 0 rows affected (0.03 sec)

mysql> explain select * from v;
+----+-------------+------------+-------+---------------+--------+---------+------+------+-------------+
| id | select_type | table      | type  | possible_keys | key    | key_len | ref  | rows | Extra       |
+----+-------------+------------+-------+---------------+--------+---------+------+------+-------------+
|  1 | PRIMARY     | <derived2> | ALL   | NULL          | NULL   | NULL    | NULL |    2 | NULL        |
|  2 | DERIVED     | t          | index | userid        | userid | 9       | NULL |    1 | Using index |
+----+-------------+------------+-------+---------------+--------+---------+------+------+-------------+
2 rows in set (0.00 sec)

到目前为止一切顺利。

现在让我们创建一个表来加入视图,并加入它。

mysql> create table u(userid int primary key, name text); 查询正常,0 行受影响(0.09 秒)

mysql> explain select * from v join u using (userid);
+----+-------------+------------+-------+---------------+-------------+---------+---------------+------+-------------+
| id | select_type | table      | type  | possible_keys | key         | key_len | ref           | rows | Extra       |
+----+-------------+------------+-------+---------------+-------------+---------+---------------+------+-------------+
|  1 | PRIMARY     | u          | ALL   | PRIMARY       | NULL        | NULL    | NULL          |    1 | NULL        |
|  1 | PRIMARY     | <derived2> | ref   | <auto_key0>   | <auto_key0> | 4       | test.u.userid |    2 | NULL        |
|  2 | DERIVED     | t          | index | userid        | userid      | 9       | NULL          |    1 | Using index |
+----+-------------+------------+-------+---------------+-------------+---------+---------------+------+-------------+
3 rows in set (0.01 sec)

我尝试使用straight_join 之类的提示来强制它读取v,然后加入u

mysql> explain select * from v straight_join u on (v.userid=u.userid);
+----+-------------+------------+-------+---------------+--------+---------+------+------+----------------------------------------------------+
| id | select_type | table      | type  | possible_keys | key    | key_len | ref  | rows | Extra                                              |
+----+-------------+------------+-------+---------------+--------+---------+------+------+----------------------------------------------------+
|  1 | PRIMARY     | <derived2> | ALL   | NULL          | NULL   | NULL    | NULL |    7 | NULL                                               |
|  1 | PRIMARY     | u          | ALL   | PRIMARY       | NULL   | NULL    | NULL |    1 | Using where; Using join buffer (Block Nested Loop) |
|  2 | DERIVED     | t          | index | userid        | userid | 9       | NULL |    7 | Using index                                        |
+----+-------------+------------+-------+---------------+--------+---------+------+------+----------------------------------------------------+

“使用连接缓冲区(块嵌套循环)”是 MySQL 的术语,表示“没有用于连接的索引”。它只是以艰难的方式遍历表格——通过从表格的开始到结束读取成批的行。

我尝试使用force index 告诉 MySQL 要避免使用type=ALL

mysql> explain select * from v straight_join u force index(PRIMARY) on (v.userid=u.userid);
+----+-------------+------------+--------+---------------+---------+---------+----------+------+-------------+
| id | select_type | table      | type   | possible_keys | key     | key_len | ref      | rows | Extra       |
+----+-------------+------------+--------+---------------+---------+---------+----------+------+-------------+
|  1 | PRIMARY     | <derived2> | ALL    | NULL          | NULL    | NULL    | NULL     |    7 | NULL        |
|  1 | PRIMARY     | u          | eq_ref | PRIMARY       | PRIMARY | 4       | v.userid |    1 | NULL        |
|  2 | DERIVED     | t          | index  | userid        | userid  | 9       | NULL     |    7 | Using index |
+----+-------------+------------+--------+---------------+---------+---------+----------+------+-------------+

也许这是使用索引进行连接?但奇怪的是,表 u 在 EXPLAIN 中的表 t 之前。坦率地说,鉴于此 EXPLAIN 报告中的行顺序,我不确定如何理解它在做什么。我希望连接的表应该在查询的主表之后

我只在每个表中放入几行数据。使用更大的代表性测试数据样本可能会得到一些不同的 EXPLAIN 结果。我会把它留给你试试。

【讨论】:

是的,谢谢比尔·卡尔文。我到处都听说视图(带有聚合)不能使用索引。这似乎是一个事实,所以如果我的视图包含超过数百行,这看起来是个坏主意。 老实说,我无法为现实世界的 mysql 中的视图找到一个有效的用例 sys 架构有很多视图来简化复杂的查询,您必须自己进行查询性能架构。此外,视图对于提供对用户通常无权查询的表的有限访问也很有用。

以上是关于MySQL:基于聚合查询的视图索引的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 索引视图:无法创建聚集索引,因为选择列表包含聚合函数结果的表达式

查询索引视图时的 WHERE 子句性能

联合分组子查询视图事务python操作mysql索引

SQL Server里面啥样的视图才能创建索引

MySQL-视图和索引

Mysql 索引视图