1

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

例如:

products有一个称为PKidusersPK 称为id。我可以创建一个日志表,每个返回的 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 的组合(替代。将这两者作为唯一索引)。

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

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

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 表增长很快。我这样做的想法是对的,还是有更好的方法?如何优化流程,是否有可以使用的工具?

4

2 回答 2

3

Callie,我只是想为 keymone 标记一个不同的观点,它不适合评论,因此这个答案。

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

你们的交易率和交易量是多少?在一天的 2 个交易高峰时段,您每分钟执行多少次插入/更新?您对日志计数器的陈旧性有哪些完整性要求?

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

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

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

您的 SQL 语句与您在 products 表中有“数百万行”的评论不相符,因为它将对 product 表执行完整的提取,并在每一行上执行相关的子查询。我自己会使用 LEFT OUTER JOIN,并带有某种强约束来过滤哪些产品项适合此结果集。无论它如何运行,执行任何计数更新都需要更长的时间。

于 2012-06-29T15:45:20.950 回答
2

使用这种方法,您的表现将非常糟糕。

mysql 并不完全适合日志记录,因此您可以执行以下几个步骤来获得良好的性能:

  1. 而不是即时维护统计表(重复密钥位的更新,这绝对会破坏您的性能),您希望拥有一个原始日志表,您将只在其中进行插入,并且不时(比如每天)您将运行将该表中的数据聚合到实际统计表中的脚本。

  2. 而不是单一的统计表 - 有一个每日统计数据,每月统计数据等。然后聚合工作将从已经聚合的东西中建立数据 - 性能非常棒。它还允许您随着时间的推移删除(或存档)统计数据粒度 - 谁在乎 2 年内的每日统计数据?或者至少是关于“实时”访问这些统计数据。

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

就是这样

于 2012-06-29T10:36:19.610 回答