插入时基于MAX()子查询安全地自动递增MySQL字段


Safely auto increment MySQL field based on MAX() subquery upon insert

我有一个表,它包含一个标准的自动递增ID、一个类型标识符、一个数字和一些其他不相关的字段。当我在这个表中插入一个新对象时,数字应该根据类型标识符自动递增。

以下是输出应该如何显示的示例:

id      type_id     number
1       1           1
2       1           2
3       2           1
4       1           3   
5       3           1
6       3           2
7       1           4
8       2           2

正如你所看到的,每次我插入一个新对象时,数字都会根据type_id递增(即,如果我插入了一个type_id为1的对象,并且已经有5个对象与这个type_id匹配,那么新对象上的数字应该是6)。

我正试图找到一种具有巨大并发性的性能方式。例如,对于相同的type_id,在同一秒内可能有300个插入,并且它们需要按顺序处理。

我已经尝试过的方法:

PHP

这是个坏主意,但为了完整起见,我添加了它。请求获取项目类型的MAX()数字,然后将数字+1作为插入的一部分添加。这很快,但不能同时工作,因为在对MAX()的请求和该特定插入之间可能有200个插入,导致多个具有相同编号和type_id的对象。

锁定

在每次插入之前和之后手动锁定和解锁工作台,以保持增量。由于并发插入的数量以及在整个应用程序中不断读取表,这导致了性能问题。

带子查询的事务

这就是我目前的做法,但它仍然会导致巨大的性能问题:

START TRANSACTION;
INSERT INTO objects (type_id,number) VALUES ($type_id, (SELECT COALESCE(MAX(number),0)+1 FROM objects WHERE type_id = $type_id FOR UPDATE));
COMMIT;

这种方法的另一个负面影响是,我需要进行后续查询,以获得添加的数字(即,搜索一个按数字desc排序的$type_id对象,这样我就可以看到创建的数字-这是基于$user_id完成的,所以它可以工作,但添加了一个我希望避免的额外查询)

触发器

我曾考虑过使用触发器在插入时动态添加数字,但这并不具有性能,因为我需要对插入的表执行查询(这是不允许的,因此必须在子查询中,这会导致性能问题)。

分组自动增量

我已经看过分组自动递增(这样数字就会根据type_id自动递增),但后来我失去了自动递增id。


有人知道我如何在我需要的并发插入级别上实现这种性能吗?我的表目前是MySQL 5.5 上的InnoDB

感谢您的帮助!

更新:对象表中有数百万个对象,以防与之相关。一些type_id可以为其分配大约500000个对象。

使用事务并选择。。。以进行更新。这将解决并发冲突。

与子查询的交易

尝试在列type_id上创建索引

我认为通过对列type_id进行索引,可以加快子查询的速度。

 DROP TABLE IF EXISTS my_table;
 CREATE TABLE my_table 
 (id      INT NOT NULL AUTO_INCREMENT PRIMARY KEY
 ,type_id     INT NOT NULL
 );
 INSERT INTO my_table VALUES
 (1,1),(2,1),(3,2),(4,1),(5,3),(6,3),(7,1),(8,2);
 SELECT x.*
      , COUNT(*) rank 
   FROM my_table x 
   JOIN my_table y 
     ON y.type_id = x.type_id 
    AND y.id <= x.id 
  GROUP 
     BY id 
  ORDER 
     BY type_id
      , rank;
 +----+---------+------+
 | id | type_id | rank |
 +----+---------+------+
 |  1 |       1 |    1 |
 |  2 |       1 |    2 |
 |  4 |       1 |    3 |
 |  7 |       1 |    4 |
 |  3 |       2 |    1 |
 |  8 |       2 |    2 |
 |  5 |       3 |    1 |
 |  6 |       3 |    2 |
 +----+---------+------+

或者,如果性能是一个问题,只需对几个@变量执行相同的操作。

也许可以为所有具有公共"type_id"的行创建一个(临时)表。在该表中,您可以对您的num colomn使用自动递增。那么你的数字应该是完全可信的。然后,您可以选择数据并更新第一个表。