自增主键超过最大值怎么办?

Din*_*ani 5 mysql primary-key

我有一个具有以下结构的表的主键,

**Field**          **Type**                  
  nid     int(10)unsigned
Run Code Online (Sandbox Code Playgroud)

我知道 int(10) 的最大限制是 4294967295。但是如果超过最大值会怎样?我应该改成 bigint 吗?如果是这样,在主键中使用 int 或 big int 的最佳做法是什么?

Rol*_*DBA 3

由于您需要转到 BIGINT,因此请为磁盘空间增长做好准备。

  • INT是4个字节
  • BIGINT 是 8 个字节

对于每个使用 INT 且您想要切换到 BIGINT 的表,您必须预测预期需要多少额外空间。

例如,要计算mydb.mytable将所有 INT(10) 列移至 BIGINT 时会增加多少空间,请运行此查询

SELECT CONCAT('SELECT COUNT(1)*',int_column_count*4,
' SizeIncreaseInBytes FROM ',table_schema,'.',table_name,';') INTO @SQLStmt
FROM (SELECT table_schema,table_name,
COUNT(1) int_column_count from
(
    SELECT table_schema,table_name,column_type
    FROM information_schema.columns
    where table_schema = 'mydb'
    AND table_name = 'mytable'
    AND column_type = 'int(10)'
) AA group by table_schema,table_name) A;
SELECT @SQLStmt;
PREPARE s FROM @SQLStmt;
EXECUTE s; DEALLOCATE PREPARE s;
Run Code Online (Sandbox Code Playgroud)

让我们使用表格dev_oxygen.bplv_reg

mysql> show create table dev_oxygen.bplv_reg\G
*************************** 1. row ***************************
       Table: bplv_reg
Create Table: CREATE TABLE `bplv_reg` (
  `id` int(11) NOT NULL DEFAULT '0',
  `firstname` varchar(40) DEFAULT NULL,
  `lastname` varchar(40) DEFAULT NULL,
  `address` varchar(255) DEFAULT NULL,
  `city` varchar(100) DEFAULT NULL,
  `state` varchar(20) DEFAULT NULL,
  `zipcode` varchar(11) DEFAULT NULL,
  `email` varchar(200) NOT NULL,
  `phone` bigint(20) DEFAULT NULL,
  `age` int(10) DEFAULT NULL,
  `newsletter` smallint(6) NOT NULL DEFAULT '0',
  `ip_address` varchar(20) DEFAULT NULL,
  `fb_user_id` int(20) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

请注意,该表的年龄为 int(10)

这是表计数:

mysql> SELECT COUNT(1) FROM dev_oxygen.bplv_reg;
+----------+
| COUNT(1) |
+----------+
|     2038 |
+----------+
1 row in set (0.00 sec)

mysql>
Run Code Online (Sandbox Code Playgroud)

现在让我们计算表必须增长的字节数:

mysql> SELECT CONCAT('SELECT COUNT(1)*',int_column_count*4,
    -> ' SizeIncreaseInBytes FROM ',table_schema,'.',table_name,';') INTO @SQLStmt
    -> FROM (SELECT table_schema,table_name,
    -> COUNT(1) int_column_count from
    -> (
    ->     SELECT table_schema,table_name,column_type
    ->     FROM information_schema.columns
    ->     where table_schema = 'dev_oxygen'
    ->     AND table_name = 'bplv_reg'
    ->     AND column_type = 'int(10)'
    -> ) AA group by table_schema,table_name) A;
Query OK, 1 row affected (0.00 sec)

mysql> SELECT @SQLStmt;
+-----------------------------------------------------------------+
| @SQLStmt                                                        |
+-----------------------------------------------------------------+
| SELECT COUNT(1)*4 SizeIncreaseInBytes FROM dev_oxygen.bplv_reg; |
+-----------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> PREPARE s FROM @SQLStmt;
Query OK, 0 rows affected (0.00 sec)
Statement prepared

mysql> EXECUTE s; DEALLOCATE PREPARE s;
+--------------------+
| SizeIncreaseInBytes|
+--------------------+
|               8152 |
+--------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql>
Run Code Online (Sandbox Code Playgroud)

该数字只是列的大小增加(以字节为单位)age

关于id?它不是 int(10) 而是 int(11)。您可以预测 int(11) 吗?当然,只需int(10)在查询中替换为int(11).

主键怎么样?如果主键有多个定义为 int(11) 的 int 列怎么办?

让我们选择一个不同的表,称为oxygen.history;

mysql> show create table oxygen.history\G
*************************** 1. row ***************************
       Table: history
Create Table: CREATE TABLE `history` (
  `uid` int(11) NOT NULL DEFAULT '0',
  `nid` int(11) NOT NULL DEFAULT '0',
  `timestamp` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`uid`,`nid`),
  KEY `nid` (`nid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> select count(1) from oxygen.history;
+----------+
| count(1) |
+----------+
|      564 |
+----------+
1 row in set (0.00 sec)

mysql>
Run Code Online (Sandbox Code Playgroud)

该表的主键有两列,两列都是int(11)

mysql> select CONCAT('SELECT COUNT(1)*',int_column_count*4,
    -> ' IndexSizeIncreaseInBytes FROM ',table_schema,'.',table_name,';')
    -> INTO @SQLStmt FROM
    -> (SELECT AA.table_schema,AA.table_name,
    -> COUNT(1) int_column_count FROM
    -> (
    ->     select table_schema,table_name,column_name
    ->     from information_schema.columns
    ->     where table_schema ='oxygen'
    ->     and table_name='history'
    ->     and column_type = 'int(11)'
    -> ) AA INNER JOIN
    -> (
    ->     select table_schema,table_name,column_name
    ->     FROM information_schema.STATISTICS
    ->     WHERE INDEX_NAME='PRIMARY'
    -> ) BB
    -> USING (table_schema,table_name,column_name)
    -> GROUP BY AA.table_schema,AA.table_name) A;
Query OK, 1 row affected (0.02 sec)

mysql> SELECT @SQLStmt;
+-----------------------------------------------------------------+
| @SQLStmt                                                        |
+-----------------------------------------------------------------+
| SELECT COUNT(1)*8 IndexSizeIncreaseInBytes FROM oxygen.history; |
+-----------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> PREPARE s FROM @SQLStmt;
Query OK, 0 rows affected (0.00 sec)
Statement prepared

mysql> EXECUTE s; DEALLOCATE PREPARE s;
+--------------------------+
| IndexSizeIncreaseInBytes |
+--------------------------+
|                     4512 |
+--------------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

mysql>
Run Code Online (Sandbox Code Playgroud)

根据主键的预测增长量,您现在可以增加这些

  • MyISAM Ke​​y Cache(如果您正在预测 MyISAM 表,其大小由key_buffer_size确定)
  • 对于 InnoDB,您可以结合上面的两个查询来测量数据,并增加索引大小以调整 InnoDB 缓冲池的大小(大小为innodb_buffer_pool_size)。