MySQL在存储和返回id方面的表现

时间:2012-06-29 09:46:17

标签: mysql sql performance

我有一个API,我需要记录查询中返回的表中的哪些ID,而在另一个查询中,返回根据id的日志排序的结果。

例如:

products有一个名为id的PK,而users有一个名为id的PK。我可以创建一个日志表,每个返回的id有一个插入/更新。我想知道性能和设计。

基本上,对于API中的每个返回的ID,我会:

INSERT INTO log (product_id, user_id, counter) 
    VALUES (@the_product_id, @the_user_id, 1) 
    ON DUPLICATE KEY UPDATE counter=counter+1;

..我要么有一个id列作为PK,要么有一个product_id和user_id的组合(alt。将这两个作为UNIQUE索引)。

所以第一个问题是这个的性能(20个插入/更新以及对我在API中的select调用的影响) - 是否有更好/更智能的方法来记录这些ID?从网络服务器日志中提取?

其次是select语句包含记录数据的性能,允许用户在每个请求中查看新产品(简化示例,我在现实生活中指定表字段而不是*):

SELECT p.*, IFNULL(
    SELECT log.counter 
    FROM log 
    WHERE log.product_id = p.id 
    AND log.user_id = @the_user_id
, 0 ) AS seen_by_user 
FROM products AS p
ORDER BY seen_by_user ASC

在我们的数据库中,products表有数百万行,而users表正在快速增长。我是否正确地想这样做,或者有更好的方法吗?如何优化流程,是否有可以使用的工具?

2 个答案:

答案 0 :(得分:3)

Callie,我只是想对keymone标记一个不同的视角,而且它不适合评论,因此这个答案。

性能对基础架构环境敏感:您是在共享托管服务(SHS),专用私有虚拟服务(PVS)还是专用服务器中运行,甚至是具有单独Web和数据库服务器的多服务器配置。

您的交易率和交易量是多少?在当天的2个交易时间内,您每分钟有多少次插入/更新?对日志计数器的陈旧性有什么要求?

是的,如果您正在进行每秒3-10次更新,那么keymone的要点是合适的,当您进入此域时,某些形式的收集过程将批量插入以允许批量插入变得至关重要。但同样重要的是Qs是存储引擎的选择,事务与批量分割以及基础架构本身的选择(服务器内数据库实例与单独的DB服务器,主/从配置......)。

但是,如果平均值<1 / sec,那么INSERT ON DUPLICATE KEY UPDATE具有与等效UPDATE语句相当的性能,如果进行单行插入/更新,它是更好的方法,因为它确保了计数的ACID完整性。

任何形式的PHP进程启动通常会在您的Web服务器上花费大约100毫秒,所以即使考虑到这一点进行异步更新也只是非常疯狂,因为性能损失明显大于更新本身。

您的SQL语句与您在产品表中有“数百万行”的注释不一致,因为它将完全获取在每一行上执行相关子查询的产品表。我自己会使用LEFT OUTER JOIN,有一些强约束来过滤哪些产品项适合这个结果集。无论它运行,执行任何计数更新都需要花费更长的时间。

答案 1 :(得分:2)

使用这种方法你会有非常糟糕的表现。

mysql不太适合日志记录,所以这里有几个步骤可以实现良好的性能:

  1. 而不是保持动态统计表(重复键位的更新,这绝对会破坏你的性能)你希望有一个原始日志表,你只需要插入和不时(例如说)每天)您将运行一个脚本,将该表中的数据聚合到实际统计表中。

  2. 而不是拥有单个统计信息表 - 具有每日统计数据,每月统计数据等。然后,聚合作业将从已经聚合的内容中构建数据 - 性能非常好。它还允许您随着时间的推移丢弃(或归档)统计数据 - 谁将关注2年内的每日统计数据?或至少对“实时”访问这些统计数据。

  3. 而不是插入到日志表中,使用类似syslog-ng的东西将这些信息收集到日志文件中(更不用说在mysql服务器上加载[s]),然后将数据从原始文本文件聚合到mysql中(这里有很多选择) ,如果你的聚合例程确实需要一些SQL灵活性,你甚至可以将原始文件导回到mysql中)

  4. 就是这样