[英]Create sql view with matching columns
我有以下表格:
Users
UserId Name
--------- --------
1 a
2 b
3 c
1 d
7 e
UsersComments
commentId Message UserId
1 aa 1
2 bb 3
3 cc 2
4 dd 3
我想创建一个视图,在其中我可以向用户推荐他们已经完成的评论量,这个想法是添加他们在网站上的一些其他交互,因此在用户表上有一个列不是解决方案。
到目前为止,我有这个查询:
CREATE VIEW userstats AS ( (SELECT UserId FROM Users) , (SELECT count(commentId) FROM UsersComments GROUP BY UserId))
问题是可能有用户尚未做任何评论,另一个问题是如何将每个用户的评论数量加入其相应的ID。
SELECT UserId, count(commentId) FROM UsersComments GROUP BY UserId
不是解决方案的原因,正如我所说,将有其他用户指标,如喜欢或上传的内容。
怎么可以这样做?
CREATE VIEW userstats
AS
SELECT
Users.UserId,
COUNT(commentId) AS n_comments
FROM
Users
LEFT JOIN
UsersComments
ON
Users.UserId=UsersComments.UserId
GROUP BY
Users.UserId;
由于Users和UsersComments表共享具有相同名称的列,因此可以使用USING
关键字而不是ON
来缩短查询:
...
LEFT JOIN
UsersComments
USING (UserId)
...
可以在不创建视图的情况下完成。
您似乎要问的问题是“什么查询可以返回指定的结果集?”
基于我们可以从您发布的语法中收集哪些信息(该查询甚至可以运行?)
这将返回指定的结果集,
SELECT u.userid
, COUNT(c.userid) AS count_usercomments
FROM users u
LEFT
JOIN usercomments c
ON c.userid = u.userid
GROUP BY u.userid
如果要创建视图,首先需要一个SELECT查询,该查询返回要返回的结果集。
由于在MySQL中使用视图所带来的性能影响(在某些情况下性能影响可以忽略不计,但在其他情况下可能会从显着到严重),我不会提供创建视图的语法。 (我认为不必要地引入视图有可能产生比通过创建视图解决的任何问题更大的问题。
跟进
问:为什么你认为观点不是一个好主意?
答:我没有说意见不是一个好主意。 我所说的是:引入一个不必要的视图有可能产生比视图作为解决方案实现的任何问题更大的问题。
当我们不了解MySQL 如何处理视图(这与在其他数据库中处理视图的方式有很大不同)时,我们可能会无意中创建一些重要的性能问题。
问:我希望能够使用结果集,但是这个查询需要花费太长时间,
A:我会喜欢小马。 和免费比萨饼。
VIEW
对象是一个查询。 每当针对VIEW执行查询时,该查询都会生成结果集。
以一个查询,“时间太长”和转弯变成一只视图定义没有做任何事情 ,以使该查询更快。
问:如果我已经有一个不断更新的视图,它会不会更快?
答:好吧,如果我们有一个正确索引的表,我们可以运行查询,这可能会使事情变得更快。
但同样,在MySQL中, VIEW
对象只是一个查询。 它不是 “不断更新”的存储结果集。
当我们运行一个引用视图的查询时(无论是在数据库中定义的VIEW
对象,还是在查询的SQL文本中定义的内联视图......执行视图查询并将返回的行具体化为MySQL指的是派生表 。
例如,这是一个包含内联视图定义的查询。 (这只是一个示例,这不是我们实际想要使用的查询示例。)
SELECT v.col
FROM (
SELECT t.col
FROM hugetable t
) v
WHERE v.col = 'foo'
执行该查询时,MySQL首先执行内联视图v
的查询。 该查询的运行方式与我们单独发出查询时的运行方式相同; 不同之处在于,该查询的结果集(即返回的行集)暂时存储为“ 派生表 ”。 (这是MySQL用于它的术语,“派生表”。
如果结果集足够小,并且它不包含MEMORY引擎不支持的任何列数据类型,MySQL将使用MEMORY引擎来存储它。 否则,MySQL使用MyISAM存储引擎,并将结果集旋转到磁盘。
填充派生表后,外部查询将使用“派生表”作为行源运行,就像常规MyISAM表一样。 派生表上没有定义索引,因此完全扫描基本上是MySQL为其提供的唯一访问方法。 外部查询将检查派生表中的每一行,以查看它是否满足外部查询中的谓词。 (MySQL 5.6.x实际上有一些改进,优化器可以在派生表上创建索引;在5.6之前,派生表上没有索引。)
查询完成后,将释放派生表。 结果集不会持久化,它已经消失了。
即使在同一会话中,对同一视图的后续引用也将导致该视图查询再次执行。
如果我们创建一个VIEW
对象,例如:
CREATE VIEW myview
AS
SELECT t.col
FROM hugetable t
我们编写一个引用VIEW
的查询,例如:
SELECT v.col
FROM myview v
WHERE v.col = 'foo'
行为是执行计划与内联视图完全相同 。 (还有一个额外的步骤,即查找视图定义,获取查询的SQL,以及某些特权检查等),但除此之外,在执行时,它的行为与内联视图完全相同。
请注意,外部查询中的谓词不会被下推到视图查询中。 并且视图没有“存储结果集”。 每次访问视图时都会实现它。
观点本身并不是一个“坏主意”。 有时候视图是返回结果集的最佳方式。 (我经常使用内联视图查询。)
问题来了,当我们不明白的观点是如何在MySQL处理。 当我们创建VIEW
对象时,这些对象往往会在其他查询中被引用,而这些查询并不是最合适的解决方案。
例如,此查询返回上面查询示例的等效结果集。 但是这里的区别在于col的谓词现在包含在视图定义中,MySQL可以有效地使用索引来消除行的大量数据,并且只访问所需的行。 这会产生一个小得多的派生表(更可能使用MEMORY引擎),外部查询将运行得更快,因为要扫描的行更少。
SELECT v.col
FROM (
SELECT h.col
FROM hugetable h
WHERE h.col = 'foo'
) v
VIEW
对象的一个问题是它“隐藏”有关查询的信息,并限制我们选择影响优化器以有效地生成结果集。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.