Mysql 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键将直接显示信息 那么,有没有人对这个特定的用例以及与之相关的性能问题有经验?对于简短的代码,可能没有什么不同。这一点尤其正确,因为包含这些代码的表可能非常小(最多几千行)

在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 | 
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|