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

时间:2013-11-26 11:26:04

标签: php mysql auto-increment

我有一个表,其中包含标准的自动递增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个插入,导致多个对象具有相同的number和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可以分配大约500,000个对象。

4 个答案:

答案 0 :(得分:1)

使用交易并选择...进行更新。这将解决并发冲突。

答案 1 :(得分:0)

使用子查询进行交易

尝试在 type_id

列上索引

我认为通过在列type_id上​​创建索引可以加快子查询的速度。

答案 2 :(得分:0)

 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 |
 +----+---------+------+

或者,如果性能是一个问题,只需对几个@variables做同样的事情。

答案 3 :(得分:0)

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