Can AUTO_INCREMENT be safely used in a BEFORE TRIGGER in MySQL

前端 未结 2 2116
被撕碎了的回忆
被撕碎了的回忆 2021-02-20 15:19

Instagram\'s Postgres method of implementing custom Ids for Sharding is great, but I need the implementation in MySQL.

So, I converted the method found at the bottom of

2条回答
  •  名媛妹妹
    2021-02-20 15:58

    The following SQL Fiddle generates an output as shown below:

    Welcome to the MySQL monitor.  Commands end with ; or \g.
    Your MySQL connection id is 45
    Server version: 5.5.35-1
    
    Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
    
    Oracle is a registered trademark of Oracle Corporation and/or its
    affiliates. Other names may be trademarks of their respective
    owners.
    
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    
    mysql> use test;
    Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A
    
    Database changed
    mysql> select `id` from `tablename`;
    +-------------------+
    | id                |
    +-------------------+
    | 11829806563853313 |
    | 11829806563853314 |
    | 11829806563853315 |
    | 11829806563853316 |
    | 11829806563853317 |
    | 11829806563853318 |
    | 11829806563853319 |
    | 11829806563853320 |
    | 11829806563853321 |
    | 11829806563853322 |
    | 11829806563853323 |
    | 11829806563853324 |
    | 11829806563853325 |
    | 11829806563853326 |
    | 11829806563853327 |
    | 11829806563853328 |
    | 11829806563853329 |
    | 11829806563853330 |
    | 11829806563853331 |
    | 11829806563853332 |
    | 11829806563853333 |
    | 11829806563853334 |
    | 11829806563853335 |
    | 11829806563853336 |
    | 11829806563853337 |
    | 11829806563853338 |
    | 11829806563853339 |
    | 11829806563853340 |
    | 11829806563853341 |
    | 11829806563853342 |
    | 11829806563853343 |
    | 11829806563853344 |
    | 11829806563853345 |
    | 11829806563853346 |
    | 11829806563853347 |
    | 11829806563853348 |
    | 11829806563853349 |
    | 11829806563853350 |
    | 11829806563853351 |
    | 11829806563853352 |
    +-------------------+
    40 rows in set (0.01 sec)
    

    Accept the answer if it really solves your need.

    UPDATE

    Welcome to the MySQL monitor.  Commands end with ; or \g.
    Your MySQL connection id is 46
    Server version: 5.5.35-1
    
    Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
    
    Oracle is a registered trademark of Oracle Corporation and/or its
    affiliates. Other names may be trademarks of their respective
    owners.
    
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    
    mysql> use test;
    Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A
    
    Database changed
    mysql> DELIMITER //
    
    mysql> DROP FUNCTION IF EXISTS `nextval`//
    Query OK, 0 rows affected, 1 warning (0.00 sec)
    
    mysql> DROP TRIGGER IF EXISTS `shard_insert`//
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> DROP TABLE IF EXISTS `tablename_seq`, `tablename`;
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> CREATE TABLE `tablename_seq` (
        ->   `seq` BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY
        -> )//
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> CREATE TABLE `tablename` (
        ->   `id` BIGINT UNSIGNED PRIMARY KEY
        -> )//
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> CREATE FUNCTION `nextval`()
        -> RETURNS BIGINT UNSIGNED
        -> DETERMINISTIC
        -> BEGIN
        ->   DECLARE `_last_insert_id` BIGINT UNSIGNED;
        ->   INSERT INTO `tablename_seq` VALUES (NULL);
        ->   SET `_last_insert_id` := LAST_INSERT_ID();
        ->   DELETE FROM `tablename_seq`
        ->   WHERE `seq` = `_last_insert_id`;
        ->   RETURN `_last_insert_id`;
        -> END//
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> CREATE TRIGGER `shard_insert` BEFORE INSERT ON `tablename`
        -> FOR EACH ROW
        -> BEGIN
        ->   DECLARE `seq_id`, `now_millis` BIGINT UNSIGNED;
        ->   DECLARE `our_epoch` BIGINT UNSIGNED DEFAULT 1314220021721;
        ->   DECLARE `shard_id` INT UNSIGNED DEFAULT 1;
        ->   SET `now_millis` := `our_epoch` + UNIX_TIMESTAMP();
        ->   SET `seq_id` := `nextval`();
        ->   SET NEW.`id` := (SELECT (`now_millis` - `our_epoch`) << 23 |
        ->                            `shard_id` << 10 |
        ->                            MOD(`seq_id`, 1024)
        ->                   );
        -> END//
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> INSERT INTO `tablename`
        -> VALUES
        -> (0), (0), (0), (0), (0),
        -> (0), (0), (0), (0), (0),
        -> (0), (0), (0), (0), (0),
        -> (0), (0), (0), (0), (0),
        -> (0), (0), (0), (0), (0),
        -> (0), (0), (0), (0), (0),
        -> (0), (0), (0), (0), (0),
        -> (0), (0), (0), (0), (0)//
    Query OK, 40 rows affected (0.00 sec)
    Records: 40  Duplicates: 0  Warnings: 0
    
    mysql> DELIMITER ;
    
    mysql> SELECT `id` FROM `tablename`;
    +-------------------+
    | id                |
    +-------------------+
    | 12581084357198849 |
    | 12581084357198850 |
    | 12581084357198851 |
    | 12581084357198852 |
    | 12581084357198853 |
    | 12581084357198854 |
    | 12581084357198855 |
    | 12581084357198856 |
    | 12581084357198857 |
    | 12581084357198858 |
    | 12581084357198859 |
    | 12581084357198860 |
    | 12581084357198861 |
    | 12581084357198862 |
    | 12581084357198863 |
    | 12581084357198864 |
    | 12581084357198865 |
    | 12581084357198866 |
    | 12581084357198867 |
    | 12581084357198868 |
    | 12581084357198869 |
    | 12581084357198870 |
    | 12581084357198871 |
    | 12581084357198872 |
    | 12581084357198873 |
    | 12581084357198874 |
    | 12581084357198875 |
    | 12581084357198876 |
    | 12581084357198877 |
    | 12581084357198878 |
    | 12581084357198879 |
    | 12581084357198880 |
    | 12581084357198881 |
    | 12581084357198882 |
    | 12581084357198883 |
    | 12581084357198884 |
    | 12581084357198885 |
    | 12581084357198886 |
    | 12581084357198887 |
    | 12581084357198888 |
    +-------------------+
    40 rows in set (0.00 sec)
    

    See db-fiddle.

提交回复
热议问题