【问题标题】:How to limit number of records in MySQL table based on certain category如何根据特定类别限制 MySQL 表中的记录数
【发布时间】:2021-08-04 11:35:01
【问题描述】:

考虑下面的“用户”表。假设我希望每个国家/地区最多允许 3 个用户(在现实世界中,这个数字可能是数千)。任何违反此条件的新插入都应该失败。有没有办法在数据库级别实现这一点,在并行插入期间保持数据一致?

用户表

ID UserName Country
1 user1 US
2 user2 US
3 user3 US
4 user4 UK
5 user5 UK
6 user6 UK
7 user7 US ---> This should fail!!

实现此目的的一种方法是在应用程序中使用 MySQL 锁定读取,例如“for update”。但这会影响并行插入期间的应用程序性能。

任何帮助将不胜感激

【问题讨论】:

  • 您可以将逻辑构建到查询本身中
  • 你使用什么版本的 MySQL?
  • 我使用的是 MySQL 5.7
  • 但这会影响并行插入期间的应用程序性能。决定什么更重要 - 性能或一致性。
  • 如果没有办法同时实现,那么我更喜欢一致性

标签: mysql locking rdbms


【解决方案1】:

使用交易(正如您提到的)是一个不错的方法。 MySQL 没有足够精细的约束系统来做你想做的事。而且,如果这样做,它对性能的影响与您提到的设置相同。

另外,您的表格不会很大(假设您只有几百个不同的 Country 值)。所以交易中的工作不会很昂贵。

这样的事情会奏效。这是一条语句,因此自动提交将起作用。

INSERT INTO Users (Username, Country) 
    SELECT :newUserName, :newCountry
     WHERE (SELECT COUNT(*) FROM Users WHERE Country = :newCountry) < 3

为什么会这样? SELECT const, const, const FROM DUAL WHERE condition 在 MySQL 中可以缩写为 SELECT const, const, const WHERE condition。他们没有接受 Oracle DUAL 的事情。如果condition 为假,则 SELECT 不返回任何行。因此,INSERT 不会插入任何行。

也可以在查询表时限制为三个条目。如果你有 MySQL 8+ 这将是微不足道的......这个查询可以做到。

SELECT ID, UserName, Country
  FROM (
        SELECT ROW_NUMBER() OVER ( PARTITION BY Country  ORDER BY ID) num,
               ID, UserName, Country
          FROM Users
  ) a
  WHERE num <= 3

然后您可以删除通宵作业或 MySQL 事件中的无关条目。

【讨论】:

  • 好吧,不是在我的(非常旧的)版本中 :-( - 但你是对的,5.7 及更高版本没问题!
  • 这会在并行插入期间处理数据一致性吗?就像同时执行 10 个插入语句,但只有 3 个插入应该成功
  • 是的,它会的。每个独立语句都作为一个事务运行。
  • MySQL 4.0 中不存在子查询——那是很久以前的事了,就像 2 年前一样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-05
  • 1970-01-01
相关资源
最近更新 更多