gio*_*ano 2 mysql primary-key auto-increment
我有一个带有自动增量主键的表。如果我想更改一行并添加新行,我会根据引擎 MyISAM 和 InnoDB 获得不同的主键。原表是:
pk.. 动物代码 动物名称 动物类别 有效日期 到期日期
1... 1... 狗... 米... 2013-10-21.... 9999-12-31
2... 2... 青蛙... ..一...2013-10-21..... 9999-12-31
如果我使用 MyISAM 运行更新/插入代码,我会得到以下信息:
pk.. 动物代码 动物名称 动物类别 有效日期 到期日期
1... 1... 狗... 米... 2013-10-21.... 2013-10-20
2... 2... 青蛙... .. 一个... 2013-10-21..... 9999-12-31
3 ... 1... 狗..... 米... 2013-10-21..... 9999 -12-31
4... 3... 猫... 米... 2013-10-21..... 9999-12-31
并使用InnoDB:pk..animal_codeanimal_nameanimal_class effective_dateexpiry_date
1...1...dogg...m...2013-10-21....2013-10-20
2...2...青蛙..... 一个... 2013-10-21..... 9999-12-31
4 ... 1... 狗..... 米... 2013-10-21.. ... 9999-12-31
5... 3... 猫... 米... 2013-10-21..... 9999-12-31
MyISAM 和 InnoDB 之间的新主键有所不同。显然,这两个引擎背后有不同的枚举范式。我只是想知道在这种特殊情况下会发生什么,即为什么InnoDB会跳转一个主键。获得此结果的代码如下。
感谢您的任何答复。
更新(2013年10月22日):
我将代码放在sqlfiddle上:http://sqlfiddle.com/#!2
/30cae/1 可以更改场景,注释掉一个引擎并在另一个引擎中注释。
首先在左侧面板上运行“构建架构”
,然后单击左侧面板上的“运行 SQL
更改场景:第 10 行和第 11 行”查看结果:
) ENGINE=MyISAM
-- ) ENGINE=INNODB
Run Code Online (Sandbox Code Playgroud)
PS:如果id之间有间隙,我没有问题,我只是想知道为什么InnoDB会跳转。
use test01;
DROP TABLE animals;
DROP TABLE stage;
/* (1) Create data base */
CREATE TABLE animals (
pk MEDIUMINT NOT NULL AUTO_INCREMENT
, animal_code INTEGER NOT NULL
, animal_name CHAR(30) NOT NULL
, animal_class CHAR(30) NOT NULL
, effective_date DATE NOT NULL
, expiry_date DATE NOT NULL
, PRIMARY KEY (pk)
-- ) ENGINE=MyISAM
) ENGINE=INNODB
;
/* (2) Create a stage table */
CREATE TABLE stage (
animal_code INTEGER NOT NULL
, animal_name CHAR(30) NOT NULL
, animal_class CHAR(30) NOT NULL
) ENGINE=MyISAM
;
/* (3.1) First import */
INSERT INTO stage (animal_code, animal_name,animal_class) VALUES
(1,'dogg','m'),(2,'frog','a')
;
/* (3.2) Second import
TRUNCATE stage;
INSERT INTO stage (animal_code, animal_name, animal_class) VALUES
(1,'dog','m'),(2,'frog','a'),(3,'cat','m')
;
*/
/* --- (4) - (6) are use as soon new data are loaded in table stage --- */
/* --- So, first insert (3.1) and run (4)-(6) --- */
/* --- Then import new data (3.2) into stage and run (4)-(6) --- */
/* (4) expire the existing product */
UPDATE
animals a
, stage b
SET
expiry_date = SUBDATE(CURRENT_DATE, 1)
WHERE
a.animal_code = b.animal_code
AND ( a.animal_name <> b.animal_name
OR b.animal_class <> b.animal_class
)
AND expiry_date = '9999-12-31'
;
/* (5) add a new row for the changing product */
INSERT INTO animals
SELECT
NULL
, b.animal_code
, b.animal_name
, b.animal_class
, CURRENT_DATE
, '9999-12-31'
FROM
animals a
, stage b
WHERE a.animal_code = b.animal_code
AND (a.animal_name <> b.animal_name
OR b.animal_class <> b.animal_class
)
AND EXISTS
(SELECT *
FROM animals x
WHERE b.animal_code = x.animal_code
AND a.expiry_date = SUBDATE(CURRENT_DATE, 1)
)
AND NOT EXISTS
(SELECT *
FROM animals y
WHERE b.animal_code = y.animal_code
AND y.expiry_date = '9999-12-31'
);
/* (6) add new product */
INSERT INTO animals
SELECT
NULL
, animal_code
, animal_name
, animal_class
, CURRENT_DATE
, '9999-12-31'
FROM stage
WHERE animal_code NOT IN(
SELECT y.animal_code
FROM animals x, stage y
WHERE x.animal_code = y.animal_code
);
Run Code Online (Sandbox Code Playgroud)
使用自动增量可以保证的是(除非您用它来重置值)生成的下一个值将高于上一个值。它通常只是更高,但你永远不应该依赖这一点:除了简单地总是增加更多细节之外,这是未定义的行为。
至于为什么不同的表类型可能会有所不同:不同的表类型在锁定/事务/并发行为方面有所不同(myISAM 非常简单/幼稚,而 InnoDB 则远不那么简单,以便提供引用完整性和性能优势)。可能是 InnoDB 很谨慎并允许并发事务,当您插入动物详细信息中的行时(步骤 5)“保留”了它认为可能需要但高估的 ID,因此没有使用其中之一,留下了间隙。myISAM 可能只是在更新期间应用了表锁,因此不会发生并发,因此它不需要在并发插入操作时保留 ID(因此,如果它高估了输出的行数,则不会留下间隙) 。