我有一个可以增长并拥有数百万行的mysql表。
我需要每次计算这些行,在同一页面中我可以为不同用户计算大约10次:
select count(id) from posts where user = ?
所以,为了避免这种情况,我正在考虑创建一个数据表,并在那里增加或减少这个数字以保持计数器。
update postscount SET number = number + 1 where user = ?
select number from postscount where user = ?
所以这个选择要快得多。
我的问题是,这是一个很好的做法,准确度如何,我有一个innodb表,它能保持准确的插入数量吗? (如果我有同时插入?)
谢谢你的朋友们!答案 0 :(得分:2)
如果id
是主键(它应该!),并且自动递增+1并且您有索引id
和user
,那么您的第一个sql应该没问题。索引和密钥在SQL中很重要。
所以,为了避免这种情况,我想创建一个数据表并增加或减少这个数字以保持计数器。
仅当您在SQL中使用触发器(在第二个表上使用Update Trigger)时,而不是使用PHP。
您还可以在表格中添加一个新字段,例如postindex
,然后您可以为新帖子中的每个用户计算个人数量并选择该字段(通过postindex DESC从用户订单中选择postindex)。
答案 1 :(得分:1)
不是为每个单独的用户计算ID,而是为了使用group by
之类的
select count(id)
from posts
group by user;
根据您的评论,如果您计算每个用户登录的帖子,请确保您在WHERE
条件(user
)中使用的列已编入索引,并且对每个用户运行查询将没事的。但创造第二张桌子是我不会做的事情,并且不会以任何方式赢得更快。您必须为update
执行两个语句,并获取number
列。
同样,您可以按照我先说的那样获取所有用户的计数,然后将其缓存在应用程序端(缓存值通常为全局),然后在所有用户会话中,您可以使用相同的缓存数据而无需触发每次都有一个单独的查询。
答案 2 :(得分:1)
我不会说这是一种很好的做法,但这是一种常见做法。我过去必须做类似的事情,特别是在容易发生不成比例的系统中。确保包含时间戳,以便了解它的计数,并根据年龄刷新/丢弃它。这应该可以降低对数据库的影响,但是在执行此类操作时应该小心。其他解决方案可能是每X个时间为每个用户计算帖子。
答案 3 :(得分:1)
通常,MySQL每个查询只使用一个索引。
对于您的查询select count(id) from posts where user = ?
,它可以是user
或id
,但可能是user
,因为它是where子句中的列。
在这种情况下,由于两列都已编制索引,您的查询将首先使用索引为用户选择行,但需要再次在id
列上搜索(使用该列的索引) ,为了计算行数,因为count()只计算不为空的值。
鉴于此,您有2个选项(无需创建新表):
选项1.显然是一个不好的选择。所以,我们使用选项2。
鉴于此,由于我们必须按user
过滤,我们会改变计数。 count(user)
是一个选项,但您也可以count(1)
。所以更好的选择是:
select count(1) from posts where user = ?
您可以通过让mysql向您解释查询来测试这两个选项,只需在其前面添加explain
。并且,为了使您的结果不受查询缓存的影响,请在选择字后添加sql_no_cache
。例如:
explain select sql_no_cache count(user) from posts where user = 1
explain select sql_no_cache count(id) from posts where user = 1
explain select sql_no_cache count(id) from posts where user = 1
比较结果。您可以检查使用哪些索引,mysql是否创建临时表等等。您可以为不同的用户制作,因为结果可能不同。
要创建一个新表,每次用户发布新帖时都会更新,为此,增益不会那么大,因为每次在帖子中插入一行(及其索引已更新)时,将在另一个表中插入/或更新新行(并更新其索引)。当然,另一个表会小很多,但每个插入都会慢一些。我没有这方面的数据。
如果它不会那么快,因为MySQL的数据量无法管理。
但是,您可以通过每X秒更新一次postcount表,每个Y用户帖子插入或使用交互等来改善这一点。在这种情况下,您可以更好地使用缓存(查询缓存,innodb缓存等),并不会遇到许多并发插入等问题。
正如其他人发布的那样,上次更新行的时间戳列可能会在X秒后强制更新。
可能每隔X秒进行一次更新,由cron / task完成,这将是一个很好的解决方案(在这种情况下,您不需要时间戳列),因为您可以利用查询缓存:启用后,mysql将每个选择查询存储在该缓存中,如果重复完全相同的查询(二进制比较)并且表没有更改,则mysql会立即返回第一个结果,而不会转到表。查看http://dev.mysql.com/doc/refman/5.7/en/query-cache.html了解详情。
您有两个选择:1)通过仅使用列的一个索引来优化您的查询,或2)创建一个包含计数的新表。
第一个选项更简单,可能适合您的系统。 100个用户并不是那么多。
第二个选项更复杂,实施起来更复杂,并且会给你带来更好的性能。
此外,通过改进Mysql服务器配置的配置,您可以提高系统性能。