如何使用MySQL InnoDB实现auto_increment复合主键?

时间:2016-07-06 14:53:52

标签: mysql composite-primary-key

我有一个表,它有一个复合主键,由一个非auto_increment列和一个auto_increment列组成。对于每个非auto_increment列值,auto_increment列需要单独递增(稍后将详细介绍)。存储引擎是InnoDB。由于性能问题,我不想锁定表。插入值后,必须有一个检索最后一个auto_increment值的方法。

以下脚本首先工作,但最后一个INSERT结果为id,checkingaccounts_id为3, 2,但需要1, 2。这就是我The auto_increment column needs to increment individually for each of the non-auto_increment column values

的意思

触发器和存储过程都是可以接受的,PHP / PDO应用程序解决方案也是可以接受的,它以某种方式模仿MySQL auto_increment行为。

mysql> EXPLAIN checkingaccounts;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| data  | varchar(45) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> EXPLAIN checks;
+---------------------+-------------+------+-----+---------+----------------+
| Field               | Type        | Null | Key | Default | Extra          |
+---------------------+-------------+------+-----+---------+----------------+
| id                  | int(11)     | NO   | PRI | NULL    | auto_increment |
| checkingaccounts_id | int(11)     | NO   | PRI | NULL    |                |
| data                | varchar(45) | YES  |     | NULL    |                |
+---------------------+-------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)

mysql> INSERT INTO checkingaccounts(id, data) VALUES(0,'bla');
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO checkingaccounts(id, data) VALUES(0,'bla');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM checkingaccounts;
+----+------+
| id | data |
+----+------+
|  1 | bla  |
|  2 | bla  |
+----+------+
2 rows in set (0.00 sec)

mysql> INSERT INTO checks(id,checkingaccounts_id,data) VALUES(0,1,'bla');
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO checks(id,checkingaccounts_id,data) VALUES(0,1,'bla');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM checks;
+----+---------------------+------+
| id | checkingaccounts_id | data |
+----+---------------------+------+
|  1 |                   1 | bla  |
|  2 |                   1 | bla  |
+----+---------------------+------+
2 rows in set (0.00 sec)

mysql> INSERT INTO checks(id,checkingaccounts_id,data) VALUES(0,2,'bla');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM checks;
+----+---------------------+------+
| id | checkingaccounts_id | data |
+----+---------------------+------+
|  1 |                   1 | bla  |
|  2 |                   1 | bla  |
|  3 |                   2 | bla  |
+----+---------------------+------+
3 rows in set (0.00 sec)

mysql>

2 个答案:

答案 0 :(得分:1)

删除auto_increment功能,改为尝试存储过程:

CREATE PROCEDURE insertChecks
     (IN AccID int(9), IN data varchar(50))
BEGIN
    DECLARE cid INT DEFAULT 1;

    SELECT (COUNT(*) + 1) INTO cid 
    FROM checks 
    WHERE checkingaccounts_id = AccID;

    INSERT INTO checks(id, checkingaccounts_id, data) 
    VALUES(cid, AccID, data);
END

并且

call insertChecks(1,'bla');
call insertChecks(1,'bla');
call insertChecks(2,'bla');

解决方案2:

CREATE PROCEDURE insertChecks 
    (IN AccID int(9), IN data varchar(50))
BEGIN
    INSERT INTO checks(id, checkingaccounts_id, data) 
        SELECT (COUNT(*) + 1), AccID, data 
        FROM checks 
        WHERE checkingaccounts_id = AccID;
END

答案 1 :(得分:0)

创建一个MyISAM表以仅创建auto_increment id,并使用触发器将此id用于目标表。如果有多个InnoDB表需要复合auto_incrementing主键,请在MyISAM表中添加一个额外的主键。

缺点:

  1. MyISAM表上不允许使用外键约束,但希望触发器可以消除风险。
  2. 需要额外的表格。
  3. 优点

    1. 如果删除主键阀,则不会重复使用。
    2. 客户端只使用普通的SQL查询,而不是存储过程。
    3. 可能比存储过程更少维护,因为向表中添加列并不需要修改触发器。
    4. enter image description here

      -- MySQL Script generated by MySQL Workbench
      -- 07/08/16 05:12:11
      -- Model: New Model    Version: 1.0
      SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
      SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
      SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
      
      -- -----------------------------------------------------
      -- Schema mydb
      -- -----------------------------------------------------
      CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
      USE `mydb` ;
      
      -- -----------------------------------------------------
      -- Table `mydb`.`a`
      -- -----------------------------------------------------
      CREATE TABLE IF NOT EXISTS `mydb`.`a` (
        `id` INT NOT NULL AUTO_INCREMENT,
        PRIMARY KEY (`id`))
      ENGINE = InnoDB;
      
      
      -- -----------------------------------------------------
      -- Table `mydb`.`t1`
      -- -----------------------------------------------------
      CREATE TABLE IF NOT EXISTS `mydb`.`t1` (
        `a_id` INT NOT NULL,
        `id` INT NOT NULL AUTO_INCREMENT,
        PRIMARY KEY (`id`, `a_id`),
        CONSTRAINT `fk_t1_a1`
          FOREIGN KEY (`a_id`)
          REFERENCES `mydb`.`a` (`id`)
          ON DELETE NO ACTION
          ON UPDATE NO ACTION)
      ENGINE = InnoDB;
      
      
      -- -----------------------------------------------------
      -- Table `mydb`.`t2`
      -- -----------------------------------------------------
      CREATE TABLE IF NOT EXISTS `mydb`.`t2` (
        `a_id` INT NOT NULL,
        `id` INT NOT NULL AUTO_INCREMENT,
        PRIMARY KEY (`id`, `a_id`),
        CONSTRAINT `fk_t2_a1`
          FOREIGN KEY (`a_id`)
          REFERENCES `mydb`.`a` (`id`)
          ON DELETE NO ACTION
          ON UPDATE NO ACTION)
      ENGINE = InnoDB;
      
      
      -- -----------------------------------------------------
      -- Table `mydb`.`t3`
      -- -----------------------------------------------------
      CREATE TABLE IF NOT EXISTS `mydb`.`t3` (
        `a_id` INT NOT NULL,
        `id` INT NOT NULL AUTO_INCREMENT,
        PRIMARY KEY (`id`, `a_id`),
        CONSTRAINT `fk_t3_a1`
          FOREIGN KEY (`a_id`)
          REFERENCES `mydb`.`a` (`id`)
          ON DELETE NO ACTION
          ON UPDATE NO ACTION)
      ENGINE = InnoDB;
      
      
      -- -----------------------------------------------------
      -- Table `mydb`.`inc`
      -- -----------------------------------------------------
      CREATE TABLE IF NOT EXISTS `mydb`.`inc` (
        `a_id` INT NOT NULL,
        `id` INT NOT NULL AUTO_INCREMENT,
        `type` CHAR(4) NOT NULL,
        PRIMARY KEY (`a_id`, `type`, `id`))
      ENGINE = MyISAM;
      
      
      SET SQL_MODE=@OLD_SQL_MODE;
      SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
      SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
      USE `mydb`;
      
      DELIMITER $$
      USE `mydb`$$
      CREATE TRIGGER `t1_BINS` BEFORE INSERT ON `t1` FOR EACH ROW
      BEGIN 
      INSERT INTO inc(a_id,type) VALUES(NEW.a_id,'t1');
      SET NEW.id=LAST_INSERT_ID();
      END$$
      
      USE `mydb`$$
      CREATE TRIGGER `t2_BINS` BEFORE INSERT ON `t2` FOR EACH ROW
      BEGIN 
      INSERT INTO inc(a_id,type) VALUES(NEW.a_id,'t2');
      SET NEW.id=LAST_INSERT_ID();
      END$$
      
      USE `mydb`$$
      CREATE TRIGGER `t3_BINS` BEFORE INSERT ON `t3` FOR EACH ROW
      BEGIN 
      INSERT INTO inc(a_id,type) VALUES(NEW.a_id,'t3');
      SET NEW.id=LAST_INSERT_ID();
      END$$
      
      
      DELIMITER ;
      

      测试

      mysql> insert into a(id) VALUES(null);
      Query OK, 1 row affected (0.00 sec)
      
      mysql> insert into t1(a_id) VALUES(1);
      Query OK, 1 row affected (0.00 sec)
      
      mysql> SELECT * FROM t1;
      +------+----+
      | a_id | id |
      +------+----+
      |    1 |  1 |
      +------+----+
      1 row in set (0.00 sec)
      
      mysql> insert into t1(a_id) VALUES(1);
      Query OK, 1 row affected (0.00 sec)
      
      mysql> insert into t1(a_id) VALUES(1);
      Query OK, 1 row affected (0.00 sec)
      
      mysql> SELECT * FROM t1;
      +------+----+
      | a_id | id |
      +------+----+
      |    1 |  1 |
      |    1 |  2 |
      |    1 |  3 |
      +------+----+
      3 rows in set (0.00 sec)
      
      mysql> insert into t2(a_id) VALUES(1);
      Query OK, 1 row affected (0.00 sec)
      
      mysql> SELECT * FROM t2;
      +------+----+
      | a_id | id |
      +------+----+
      |    1 |  1 |
      +------+----+
      1 row in set (0.00 sec)
      
      mysql> insert into a(id) VALUES(null);
      Query OK, 1 row affected (0.00 sec)
      
      mysql> insert into a(id) VALUES(null);
      Query OK, 1 row affected (0.00 sec)
      
      mysql> insert into t1(a_id) VALUES(2);
      Query OK, 1 row affected (0.00 sec)
      
      mysql> insert into t1(a_id) VALUES(3);
      Query OK, 1 row affected (0.00 sec)
      
      mysql> insert into t1(a_id) VALUES(1);
      Query OK, 1 row affected (0.00 sec)
      
      mysql> SELECT * FROM t1;
      +------+----+
      | a_id | id |
      +------+----+
      |    1 |  1 |
      |    1 |  2 |
      |    1 |  3 |
      |    1 |  4 |
      |    2 |  1 |
      |    3 |  1 |
      +------+----+
      6 rows in set (0.00 sec)
      
      mysql>
      
相关问题