【问题标题】:InnoDB and count: Are helper tables the way to go?InnoDB 和计数:辅助表是要走的路吗?
【发布时间】:2014-01-04 20:10:30
【问题描述】:

假设我在 MySQL/InnoDB 上有一个包含 100 万用户的 users 表:

用户

  • userId(主键,整数)
  • 状态(整数)
  • 更多数据

如果我想准确计算status = 1(表示激活帐户)的用户数量,那么大桌子的方法是什么,我的想法是:

用户数

  • 状态
  • 计数

然后在users 上运行TRIGGER AFTER INSERT 以更新usercounts 中的相应列

这是最好的方法吗?

ps。一个额外的小问题:因为当status 更改时,您还需要在users 上使用TRIGGER AFTER UPDATE,因此是否有可用的语法:

  • 涵盖status 上的TRIGGER AFTER INSERTTRIGGER AFTER UPDATE
  • 如果count 已经存在,则将count 加一,否则插入新的(status, count = 0) 对?

【问题讨论】:

  • users 表中插入/更新行的频率如何?状态的有效值是什么?只有01 还是有其他的?
  • @peterm 这只是一个概念性的例子,但一个例子可以是状态:1 = ok,2 = deleted,3 = 禁止。并且插入只会偶尔发生一次,但是更新会发生很多,但不会发生在 status 字段本身。

标签: mysql sql performance triggers innodb


【解决方案1】:

这是最好的方法吗?

是否最好(基于意见),但这绝对是一种可行的方法。

是否有可用的语法:同时涵盖 TRIGGER AFTER INSERT 和 TRIGGER AFTER UPDATE 状态?

没有。 MySQL 中没有复合触发器语法。您必须创建单独的触发器。

是否有可用的语法:如果计数已经存在,则将计数加一,否则插入一个新的 (status, count = 0) 对?

是的。您可以在INSERT 语句中使用ON DUPLICATE KEY 子句。确保statususercounts 表中的PK。

现在如果用户可以被删除,即使只是出于维护目的,您还需要使用AFTER DELETE 触发器来覆盖它。


话虽如此,您的触发器可能看起来像

CREATE TRIGGER tg_ai_users
AFTER INSERT ON users
FOR EACH ROW
  INSERT INTO usercounts (status, cnt)
  VALUES (NEW.status, 1)
  ON DUPLICATE KEY UPDATE cnt = cnt + 1;

CREATE TRIGGER tg_ad_users
AFTER DELETE ON users
FOR EACH ROW
    UPDATE usercounts 
       SET cnt = cnt - 1
     WHERE status = OLD.status;

DELIMITER $$
CREATE TRIGGER tg_au_users
AFTER UPDATE ON users
FOR EACH ROW
BEGIN
  IF NOT NEW.status <=> OLD.status THEN -- proceed ONLY if status has been changed
    UPDATE usercounts 
       SET cnt = cnt - 1
     WHERE status = OLD.status;
    INSERT INTO usercounts (status, cnt) VALUES (NEW.status, 1)
    ON DUPLICATE KEY UPDATE cnt = cnt + 1;
  END IF;
END$$
DELIMITER ;

最初填充usercounts 表使用

INSERT INTO usercounts (status, cnt)
SELECT status, COUNT(*)
  FROM users
 GROUP BY status

这里是SQLFiddle演示

【讨论】:

  • 是否有任何理由在我的数据库(10K 用户)上,有时需要 0.03 秒,但有时需要 4 秒?或者原因会在共享虚拟主机中的某个地方。
  • 更新100条随机记录的连续结果:0.03s、0.3s、0.98s、0.07s、0.20s、0.82s、0.09s。可能是数据库?
  • 为了将来参考,您可能想解释一下NOT x &lt;=&gt; y 的作用,不过我只是自己想通了
  • 在任何与性能相关的问题中,几乎不可能说出没有看到和基准测试真实系统的智能。现在它可能是这种方法的一个缺点(锁定等待),这是由usercounts 表中的这三个记录的并发处理“战斗”引起的。使用SHOW ENGINE INNODB STATUS 检查是否是这种情况。这是关于该主题的article
  • 关于 null 安全比较:如果有人在他的答案中解释所有内容,那么就没有什么能引起读者的注意了...... :) 太好了,你自己想出来了。跨度>
【解决方案2】:

我认为您可以使用更简单的选项。

只需将索引添加到您想要依赖的字段即可。

ALTER TABLE 用户添加键(状态);

现在选择应该非常快。

SELECT COUNT(*) FROM users WHERE status = 1

【讨论】:

  • 我已经看到几个小时的案例,在稍微复杂的表上执行这种语法会使我的查询花费接近 0.4 秒,我认为COUNT(*) 是这里的主要罪魁祸首,链接到其他问题:stackoverflow.com/questions/20924951/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-12
  • 2021-12-14
  • 1970-01-01
  • 1970-01-01
  • 2011-11-10
  • 1970-01-01
  • 2017-01-30
相关资源
最近更新 更多