我有以下表格:
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
不是解决方案的原因,正如我所说的,会有其他用户指标,如喜欢或上传的内容。
怎么可以这样做?
答案 0 :(得分:2)
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)
...
答案 1 :(得分:1)
可以在不创建视图的情况下完成。
您似乎要问的问题是"什么查询可以返回指定的结果集?"
基于我们可以从您发布的语法中收集哪些信息(该查询甚至可以运行?)
这将返回指定的结果集
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中使用视图所带来的性能影响(在某些情况下性能影响可以忽略不计,但在其他情况下可能从重要到严重),我不打算提供创建视图的语法。 (我认为不必要地引入视图有可能产生比通过创建视图解决的任何问题更大的问题。
<强>后续强>
问:为什么您认为观点不是一个好主意?
答:我没有说这些观点不是一个好主意。我所说的是:引入一个不必要的视图有 potential 来创建更大的问题,而不是视图作为解决方案实现的任何问题。
如果我们不了解如何 MySQL处理视图(这与在其他数据库中处理视图的方式有很大不同),我们可能会无意中创建一些重大的性能问题。
问:我希望能够使用结果集,但是这些查询需要花费太长时间,
A:我会爱上一匹小马。还有免费比萨饼。
VIEW
对象是一个查询。每当针对VIEW执行查询时,该查询都会生成结果集。
查询&#34;花费太长时间&#34;并将其转换为视图定义并不会任何以使查询更快。
问:如果我的视图不断更新会不会更快?
答:好吧,如果我们有一个正确索引的表,我们可以运行查询,这可能会使事情变得更快。
但同样,在MySQL中,VIEW
对象只是一个查询。 不存储的结果集是&#34;不断更新&#34;。
当我们运行引用视图的查询时(无论是在数据库中定义的&#39; sa VIEW
对象,还是在查询的SQL文本中定义的内联视图...视图查询是执行并返回的行被实现为MySQL所指的派生表。
例如,这是一个包含内联视图定义的查询。 (这只是一个示例,这是不我们实际想要使用的查询示例。)
SELECT v.col
FROM (
SELECT t.col
FROM hugetable t
) v
WHERE v.col = 'foo'
执行该查询时,MySQL首先执行内联视图v
的查询。该查询的运行方式与我们单独发出查询时的运行方式相同;不同之处在于,该查询的结果集(即返回的行集)暂时存储为&#34; 派生表&#34;。 (这是MySQL用于它的术语,&#34;派生表&#34;。
如果结果集足够小,并且它不包含MEMORY引擎不支持的任何列数据类型,MySQL将使用MEMORY引擎来存储它。否则,MySQL使用MyISAM存储引擎,并将结果集旋转到磁盘。
填充派生表后,使用&#34;派生表&#34;运行外部查询。作为rowsource,就像常规的MyISAM表一样。派生表上没有定义索引,因此完全扫描基本上是MySQL为其提供的唯一访问方法。外部查询将检查派生表中的每一行,以查看它是否满足外部查询中的谓词。 (MySQL 5.6.x实际上有一些改进,优化器可以在派生表上创建索引;在5.6之前,派生表上有 no 索引。)
查询完成后,将释放派生表。结果集没有持久化,它已经消失了。
即使在同一会话中,对同一视图的后续引用也会导致该视图查询再次执行。
如果我们创建一个VIEW
对象,例如:
CREATE VIEW myview
AS
SELECT t.col
FROM hugetable t
我们编写一个引用VIEW
的查询,例如:
SELECT v.col
FROM myview v
WHERE v.col = 'foo'
行为是执行计划完全与内联视图相同。 (还有一个额外的步骤,即查找视图定义,获取查询的SQL,以及某些特权检查等),但除此之外,在执行时,它的行为与内联完全相同图。
请注意,外部查询中的谓词 not 会被推送到视图查询中。并且没有&#34;存储的结果集&#34;为了观点。每次访问视图时都会实现它。
观点不是一个坏主意&#34;本身。有时候视图是返回结果集的最佳方式。 (我经常使用内联视图查询。)
当我们不了解如何在MySQL中处理视图时,会出现问题。当我们创建VIEW
个对象时,这些对象往往会在其他查询中被引用,而这些查询并不是最合适的解决方案。
例如,此查询返回上面查询示例的等效结果集。但是这里的区别在于col的谓词现在包含在视图定义中,MySQL可以有效地使用索引来消除行的大量数据,并且只访问所需的行。这会产生一个小得多的派生表(更有可能使用MEMORY引擎),外部查询运行得更快,因为要扫描的行数较少。
SELECT v.col
FROM (
SELECT h.col
FROM hugetable h
WHERE h.col = 'foo'
) v
VIEW
对象的一个问题是它隐藏了&#34;有关查询的信息,并限制我们影响优化器以有效生成结果集的选项。