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));
如果您进行聚合以获取每个userid
的note
的总和,它会对(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:基于聚合查询的视图索引的主要内容,如果未能解决你的问题,请参考以下文章