DBD::DB2:为什么 `$dbh->disconnect` 会导致自动增量列中出现间隙?

sid*_*com 1 db2 perl dbi auto-increment

为什么会$dbh->disconnect导致自增列出现间隙?

use DBI;

my $db = 'MYDB2';
my $table = 'SCHEMA.TABLE';
my $user = 'user';
my $pass = 'passwd';
my $dsn = "dbi:DB2:$db";

my $dbh = DBI->connect( $dsn, $user, $pass );
$dbh->do( "DROP TABLE IF EXISTS $table" );
$dbh->do( "CREATE TABLE $table (ID INT NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, NAME CHAR(3))" );
my $sth = $dbh->prepare( "INSERT INTO $table (NAME) VALUES(?)" );
$sth->execute( 'aaa' );
$sth->execute( 'bbb' );
$sth = $dbh->prepare( "SELECT * FROM $table" );
$sth->execute();
$sth->dump_results;
$sth->finish;
$dbh->disconnect;

$dbh = DBI->connect( $dsn, $user, $pass );
$sth = $dbh->prepare( "INSERT INTO $table (NAME) VALUES(?)" );
$sth->execute( 'ccc' );
$sth->execute( 'ddd' );
$sth = $dbh->prepare( "SELECT * FROM $table" );
$sth->execute();
$sth->dump_results;
Run Code Online (Sandbox Code Playgroud)
'1', 'aaa'
'2', 'bbb'
2 rows
'1', 'aaa'
'2', 'bbb'
'21', 'ccc'
'22', 'ddd'
4 rows
Run Code Online (Sandbox Code Playgroud)

如果没有disconnect自动增量列,则创建的列没有间隙:

use DBI;

my $db = 'MYDB2';
my $table = 'SCHEMA.TABLE';
my $user = 'user';
my $pass = 'passwd';
my $dsn = "dbi:DB2:$db";

my $dbh = DBI->connect( $dsn, $user, $pass );
$dbh->do( "DROP TABLE IF EXISTS $table" );
$dbh->do( "CREATE TABLE $table (ID INT NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY, NAME CHAR(3))" );
my $sth = $dbh->prepare( "INSERT INTO $table (NAME) VALUES(?)" );
$sth->execute( 'aaa' );
$sth->execute( 'bbb' );
$sth = $dbh->prepare( "SELECT * FROM $table" );
$sth->execute();
$sth->dump_results;
$sth->finish;
#$dbh->disconnect;

$dbh = DBI->connect( $dsn, $user, $pass );
$sth = $dbh->prepare( "INSERT INTO $table (NAME) VALUES(?)" );
$sth->execute( 'ccc' );
$sth->execute( 'ddd' );
$sth = $dbh->prepare( "SELECT * FROM $table" );
$sth->execute();
$sth->dump_results;
Run Code Online (Sandbox Code Playgroud)
'1', 'aaa'
'2', 'bbb'
2 rows
'1', 'aaa'
'2', 'bbb'
'3', 'ccc'
'4', 'ddd'
4 rows
Run Code Online (Sandbox Code Playgroud)

mao*_*mao 5

这是按设计工作的,不保证始终生成的 IDENTITY 列是连续的,并且应该预期会有间隙。

这与 Perl 或 DBD:DB2 无关,这只是 Db2 实现始终生成的标识列的方式。Db2 在内部为每个连接的此类列维护一个小型的标识值值缓存,并且在消耗某个值的事务回滚之后、崩溃或异常终止之后、或者其他应用程序(其他连接)正在插入时,您可能会出现间隙值插入同一标识列,或者增量/减量值不是 1,或者数据库停用。

尽管您可以在指定标识列时使用“NO CACHE”选项,或指定较低的缓存值,但出于性能/并发原因,这些选项是不可取的。

您还可以通过安排在第一次连接发生之前显式激活数据库来减少数据库停用(但不能消除它)db2 activate database $dbname。这将确保当最后一个连接断开连接时,数据库不会自动停用,并且在这种情况下,标识列的预分配数字的缓存不会丢失。

如果您想强制执行零间隙,则必须使用不同的技术,这通常会对高插入频率应用程序和/或可扩展性/并发挑战产生性能影响。