MySQL获得下一个唯一值而无需自动增量

我有一个MySQL数据库(InnoDB),我正在开发用于跟踪我的组织的工作订单.有多个“站点”,每个站点的工单号从100开始.

WorkorderID    SiteID    SiteWorkorderNum
     1           1            100
     2           1            101
     3           2            100

WorkorderID是自动增量字段.
SiteID和SiteWorkorderNum都设置为唯一约束.

每当要为特定站点插入新的工作单时,应用程序将检查登录的siteid的max(SiteWorkorderNum)并将该值返回到insert语句.我想避免的问题是,同一站点的两个用户是否在同一时间输入新的工单.

我有几个可能的解决方案,但我想看看是否有更好的方法,因为每个都有它的缺点,但我肯定会比另一个更好,当然我对新想法持开放态度.

1)锁定表以保证在我们检索并插入我们的值之前没有其他用户检索SiteWorkorderNum值(但是假设我们有数千个用户试图每分钟输入工作订单,表格锁定会不会减慢速度? )

2)不要锁定表,并检索下一个可用的SiteWorkorderNum并尝试插入数据库,如果我收到唯一约束错误,请捕获错误并再试一次,直到我成功. (这可能会让表格*释放,但是再次假装我们在同一个站点有数千个用户,多个数据库调用会不会有点低效?)

对于这些解决方案中的任何一种“如何”影响性能,我是否过于偏执?当然我没有成千上万的用户,但我想在这个设计中应用最佳实践,以防我曾经在一个流量很高的项目上工作.

解决方法:

使用MyISAM存储可以解决这种情况的有趣之处.

我在2012年4月回答了这样的问题:How can you have two auto-incremental columns in one table?您需要创建一个表,其唯一目的是为每个站点创建工作单序列

CREATE TABLE site_workorder_seq
(
    SiteID int not null,
    SiteWorkorderNum int not null auto_increment,
    PRIMARY KEY (SiteID,SiteWorkorderNum)
) ENGINE=MyISAM;

以下是加载到此表中的示例:

mysql>     DROP DATABASE david;
Query OK, 1 row affected (0.01 sec)

mysql>     CREATE DATABASE david;
Query OK, 1 row affected (0.00 sec)

mysql>     USE david
Database changed
mysql>     CREATE TABLE site_workorder_seq
    ->     (
    ->         SiteID int not null,
    ->         SiteWorkorderNum int not null auto_increment,
    ->         PRIMARY KEY (SiteID,SiteWorkorderNum)
    ->     ) ENGINE=MyISAM;
Query OK, 0 rows affected (0.01 sec)

mysql>     INSERT INTO site_workorder_seq (SiteID) VALUES
    ->     (1),(1),(2),(3),(3),(3),(3),(4),(4),(4),
    ->     (5),(5),(4),(2),(2),(2);
Query OK, 16 rows affected (0.00 sec)
Records: 16  Duplicates: 0  Warnings: 0

mysql>     SELECT * FROM site_workorder_seq;
+--------+------------------+
| SiteID | SiteWorkorderNum |
+--------+------------------+
|      1 |                1 |
|      1 |                2 |
|      2 |                1 |
|      2 |                2 |
|      2 |                3 |
|      2 |                4 |
|      3 |                1 |
|      3 |                2 |
|      3 |                3 |
|      3 |                4 |
|      4 |                1 |
|      4 |                2 |
|      4 |                3 |
|      4 |                4 |
|      5 |                1 |
|      5 |                2 |
+--------+------------------+
16 rows in set (0.00 sec)

mysql>

让我们看看每个站点的最后一个WorkorderNum

mysql> SELECT SiteID,MAX(SiteWorkorderNum) SiteWorkorderNum
    -> FROM site_workorder_seq GROUP BY SiteID;
+--------+------------------+
| SiteID | SiteWorkorderNum |
+--------+------------------+
|      1 |                2 |
|      2 |                4 |
|      3 |                4 |
|      4 |                4 |
|      5 |                2 |
+--------+------------------+
5 rows in set (0.05 sec)

mysql>

现在,假设您想要获取SiteID 3的下一个SiteWorkorderNum.您可以这样做:

INSERT INTO site_workorder_seq (SiteID) VALUES (3);
SELECT MAX(SiteWorkorderNum) INTO @nextworkordernum
FROM site_workorder_seq WHERE SiteID=3;
SELECT @nextworkordernum;

让我们运行它,看看会发生什么

mysql> INSERT INTO site_workorder_seq (SiteID) VALUES (3);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT MAX(SiteWorkorderNum) INTO @nextworkordernum
    -> FROM site_workorder_seq WHERE SiteID=3;
Query OK, 1 row affected (0.00 sec)

mysql> SELECT @nextworkordernum;
+-------------------+
| @nextworkordernum |
+-------------------+
|                 5 |
+-------------------+
1 row in set (0.03 sec)

mysql> SELECT * FROM site_workorder_seq;
+--------+------------------+
| SiteID | SiteWorkorderNum |
+--------+------------------+
|      1 |                1 |
|      1 |                2 |
|      2 |                1 |
|      2 |                2 |
|      2 |                3 |
|      2 |                4 |
|      3 |                1 |
|      3 |                2 |
|      3 |                3 |
|      3 |                4 |
|      3 |                5 |
|      4 |                1 |
|      4 |                2 |
|      4 |                3 |
|      4 |                4 |
|      5 |                1 |
|      5 |                2 |
+--------+------------------+
17 rows in set (0.00 sec)

mysql> SELECT SiteID,MAX(SiteWorkorderNum) SiteWorkorderNum
    -> FROM site_workorder_seq GROUP BY SiteID;
+--------+------------------+
| SiteID | SiteWorkorderNum |
+--------+------------------+
|      1 |                2 |
|      2 |                4 |
|      3 |                5 |
|      4 |                4 |
|      5 |                2 |
+--------+------------------+
5 rows in set (0.00 sec)

mysql>

只要您使用MyISAM除了所有InnoDB表之外,您就可以根据自己的内容为每个站点生成workordernums.

上一篇:仅当列具有特定值时,MySQL唯一索引


下一篇:mysql – 使字段唯一使其编入索引吗?