Mysql INT和VARCHAR主键之间是否存在真正的性能差异?
在MySQL中使用INT和VARCHAR作为主键是否存在可测量的性能差异?我想使用VARCHAR作为参考列表的主键(想想美国的州、国家代码),同事不会将INT AUTO_增量作为所有表的主键 我的论点(如详细所述)是INT和VARCHAR之间的性能差异可以忽略不计,因为每个INT外键引用都需要一个连接来理解引用,VARCHAR键将直接显示信息Mysql INT和VARCHAR主键之间是否存在真正的性能差异?,mysql,performance,primary-key,innodb,myisam,Mysql,Performance,Primary Key,Innodb,Myisam,在MySQL中使用INT和VARCHAR作为主键是否存在可测量的性能差异?我想使用VARCHAR作为参考列表的主键(想想美国的州、国家代码),同事不会将INT AUTO_增量作为所有表的主键 我的论点(如详细所述)是INT和VARCHAR之间的性能差异可以忽略不计,因为每个INT外键引用都需要一个连接来理解引用,VARCHAR键将直接显示信息 那么,有没有人对这个特定的用例以及与之相关的性能问题有经验?对于简短的代码,可能没有什么不同。这一点尤其正确,因为包含这些代码的表可能非常小(最多几千行)
那么,有没有人对这个特定的用例以及与之相关的性能问题有经验?对于简短的代码,可能没有什么不同。这一点尤其正确,因为包含这些代码的表可能非常小(最多几千行),并且不会经常更改(上次添加新的美国州是在什么时候)
对于键之间变化较大的较大表,这可能是危险的。例如,考虑使用用户表中的电子邮件地址/用户名。当您有数百万用户,其中一些用户的姓名或电子邮件地址较长时会发生什么情况。现在,每当您需要使用该键加入此表时,它都会变得非常昂贵。这与性能无关。这是关于什么是一个好的主键。随着时间的推移,它是独一无二的、不变的。您可能认为一个实体(如国家代码)永远不会随着时间的推移而改变,是主键的理想候选。但痛苦的经验是,这种情况很少发生 INT AUTO_增量满足“唯一且随时间不变”条件。因此偏好。绝对不是 我已经做了几件。。。几个INT、VARCHAR和CHAR之间的性能检查 1000万个主键记录表(唯一和集群)具有完全相同的速度和性能(以及子树成本),无论我使用的是哪一个
话虽如此。。。使用最适合您的应用程序的东西。不要担心性能。至于主键,任何物理上使行唯一的东西都应该被确定为主键 对于作为外键的引用,使用自动递增整数作为代理是一个好主意,主要原因有两个。
-首先,通常在联接中产生的开销较少。
-其次,如果需要更新包含唯一varchar的表,那么更新必须级联到所有子表,并更新所有子表以及索引,而使用int代理,它只需要更新主表及其索引 使用代理的缺点是,您可能允许更改代理的含义:
ex.
id value
1 A
2 B
3 C
Update 3 to D
id value
1 A
2 B
3 D
Update 2 to C
id value
1 A
2 C
3 D
Update 3 to B
id value
1 A
2 C
3 B
这完全取决于您在结构中真正需要担心什么以及什么是最重要的。不确定性能影响,但至少在开发过程中,似乎有一种可能的折衷办法,即既包括自动递增的整数“代理”键,也包括您预期的唯一“自然”键。这将使您有机会评估性能以及其他可能的问题,包括自然键的可更改性。您可以通过使用所谓的a而不是a来避免一些连接查询。只有您可以评估这在您的应用程序中是否具有重要意义 也就是说,您可以度量应用程序中最重要的查询,因为它们处理大量数据或执行非常频繁。如果这些查询从消除连接中受益,并且使用varchar主键不会造成问题,那么就这样做 不要对数据库中的所有表使用这两种策略。在某些情况下,自然密钥可能更好,但在其他情况下,代理密钥更好
其他人提出了一个很好的观点,即在实践中,自然关键点很少发生变化或重复,因此代理关键点通常是值得的。取决于长度。。如果varchar是20个字符,int是4,那么如果您使用int,您的索引在磁盘上每页的索引空间将有五倍的节点数。。。这意味着遍历索引将需要五分之一的物理和/或逻辑读取 因此,如果性能是一个问题,如果有机会,请始终为表和引用这些表中的行的外键使用一个完整的无意义键(称为代理项) 同时,为了保证数据的一致性,每个重要的表也应该有一个有意义的非数字备用键(或唯一索引),以确保不能插入重复的行(基于有意义的表属性进行复制)
对于您正在讨论的特定用途(如状态查找),它实际上并不重要,因为表的大小非常小。。一般来说,索引对少于几千行的表的性能没有影响 在HauteLook,我们更改了许多表,以使用自然键。我们确实体验到了真实世界中性能的提高。正如您所提到的,我们的许多查询现在使用较少的联接,这使得查询的性能更高。如果有意义的话,我们甚至会使用复合主键。也就是说,如果某些表有代理键,它们就更容易使用
此外,如果您允许用户向数据库编写接口,代理键也会很有帮助。第三方可以依赖这样一个事实:代理密钥只有在非常罕见的情况下才会更改。我也面临同样的困境。我制作了一个包含3个事实表的DW(星座图),包括道路事故、事故中的车辆和事故中的伤亡。数据包括1979年至2012年英国记录的所有事故,以及60个维度表。总共大约有2000万条记录。
+----------+ +---------+
| Accident |>--------<| Vehicle |
+-----v----+ 1 * +----v----+
1| |1
| +----------+ |
+---<| Casualty |>---+
* +----------+ *
CREATE TABLE map (
id ... AUTO_INCREMENT,
foo_id ...,
bar_id ...,
PRIMARY KEY(id),
UNIQUE(foo_id, bar_id),
INDEX(bar_id) );
CREATE TABLE map (
# No surrogate
foo_id ...,
bar_id ...,
PRIMARY KEY(foo_id, bar_id),
INDEX (bar_id, foo_id) );
country_id INT ...
-- versus
country_code CHAR(2) CHARACTER SET ascii
create table jan_int (data1 varchar(255), data2 int(10), myindex tinyint(4)) ENGINE=InnoDB;
create table jan_int_index (data1 varchar(255), data2 int(10), myindex tinyint(4), INDEX (myindex)) ENGINE=InnoDB;
create table jan_char (data1 varchar(255), data2 int(10), myindex char(6)) ENGINE=InnoDB;
create table jan_char_index (data1 varchar(255), data2 int(10), myindex char(6), INDEX (myindex)) ENGINE=InnoDB;
create table jan_varchar (data1 varchar(255), data2 int(10), myindex varchar(63)) ENGINE=InnoDB;
create table jan_varchar_index (data1 varchar(255), data2 int(10), myindex varchar(63), INDEX (myindex)) ENGINE=InnoDB;
$pdo = get_pdo();
$keys = [ 'alabam', 'massac', 'newyor', 'newham', 'delawa', 'califo', 'nevada', 'texas_', 'florid', 'ohio__' ];
for ($k = 0; $k < 10; $k++) {
for ($j = 0; $j < 1000; $j++) {
$val = '';
for ($i = 0; $i < 1000; $i++) {
$val .= '("' . generate_random_string() . '", ' . rand (0, 10000) . ', "' . ($keys[rand(0, 9)]) . '"),';
}
$val = rtrim($val, ',');
$pdo->query('INSERT INTO jan_char VALUES ' . $val);
}
echo "\n" . ($k + 1) . ' millon(s) rows inserted.';
}
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Name | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Collation |
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| jan_int | InnoDB | 10 | Dynamic | 9739094 | 43 | 422510592 | 0 | 0 | 4194304 | NULL | utf8mb4_unicode_520_ci |
| jan_int_index | InnoDB | 10 | Dynamic | 9740329 | 43 | 420413440 | 0 | 132857856 | 7340032 | NULL | utf8mb4_unicode_520_ci |
| jan_char | InnoDB | 10 | Dynamic | 9726613 | 51 | 500170752 | 0 | 0 | 5242880 | NULL | utf8mb4_unicode_520_ci |
| jan_char_index | InnoDB | 10 | Dynamic | 9719059 | 52 | 513802240 | 0 | 202342400 | 5242880 | NULL | utf8mb4_unicode_520_ci |
| jan_varchar | InnoDB | 10 | Dynamic | 9722049 | 53 | 521142272 | 0 | 0 | 7340032 | NULL | utf8mb4_unicode_520_ci |
| jan_varchar_index | InnoDB | 10 | Dynamic | 9738381 | 49 | 486539264 | 0 | 202375168 | 7340032 | NULL | utf8mb4_unicode_520_ci |
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|