【问题标题】:Does adding a unique constraint slow down things?添加唯一约束会减慢速度吗?
【发布时间】:2011-04-21 02:05:40
【问题描述】:

我的表中有三列。

+-----------+-----------------------+------+-----+---------+-------+
| Field     | Type                  | Null | Key | Default | Extra |
+-----------+-----------------------+------+-----+---------+-------+
| hash      | mediumint(8) unsigned | NO   | PRI | 0       |       | 
| nums      | int(10) unsigned      | NO   | PRI | 0       |       | 
| acc       | smallint(5) unsigned  | NO   | PRI | 0       |       | 
+-----------+-----------------------+------+-----+---------+-------+

我预计我的数据中有重复项,因此我继续添加了一个唯一约束:

ALTER TABLE nt_accs ADD UNIQUE(hash,nums,acc);

我有大约 5 亿行要插入到该表中,并且该表已使用 RANGE 对 nums 进行了大约 20 个分区。

  1. 唯一约束是否会减慢插入速度?这与只创建主键而不是施加唯一约束有何不同?
  2. 我有很多GROUP BY 类型的查询同时使用hash 和nums 列。我是继续添加convering index on,还是只添加单个索引?

编辑:

在分区和插入一些测试数据后解释计划

1. mysql> explain partitions select * from nt_accs;
+----+-------------+-----------+---------------------------------------------------------------------------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table     | partitions                                                                | type  | possible_keys | key      | key_len | ref  | rows | Extra       |
+----+-------------+-----------+---------------------------------------------------------------------------+-------+---------------+----------+---------+------+------+-------------+
|  1 | SIMPLE      | nt_accs   | p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20 | index | NULL          | hash     | 7       | NULL |   10 | Using index | 
+----+-------------+-----------+---------------------------------------------------------------------------+-------+---------------+----------+---------+------+------+-------------+
1 row in set (0.00 sec)



2. mysql> explain partitions select * from nt_accs WHERE nums=1504887570;
+----+-------------+-----------+------------+-------+---------------+----------+---------+------+------+--------------------------+
| id | select_type | table     | partitions | type  | possible_keys | key      | key_len | ref  | rows | Extra                    |
+----+-------------+-----------+------------+-------+---------------+----------+---------+------+------+--------------------------+
|  1 | SIMPLE      | nt_accs   | p7         | index | NULL          | hash     | 7       | NULL |   10 | Using where; Using index | 
+----+-------------+-----------+------------+-------+---------------+----------+---------+------+------+--------------------------+
1 row in set (0.00 sec)

3. mysql> explain partitions select * from nt_accs WHERE hash=2347200;
+----+-------------+-----------+---------------------------------------------------------------------------+------+---------------+----------+---------+-------+------+-------------+
| id | select_type | table     | partitions                                                                | type | possible_keys | key      | key_len | ref   | rows | Extra       |
+----+-------------+-----------+---------------------------------------------------------------------------+------+---------------+----------+---------+-------+------+-------------+
|  1 | SIMPLE      | nt_accs  | p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20 | ref  | hash          | hash     | 3       | const |   27 | Using index | 
+----+-------------+-----------+---------------------------------------------------------------------------+------+---------------+----------+---------+-------+------+-------------+
1 row in set (0.00 sec)

4. mysql> EXPLAIN PARTITIONS SELECT hash, count(distinct nums) FROM nt_accs GROUP BY hash;
+----+-------------+-----------+---------------------------------------------------------------------------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table     | partitions                                                                | type  | possible_keys | key      | key_len | ref  | rows | Extra       |
+----+-------------+-----------+---------------------------------------------------------------------------+-------+---------------+----------+---------+------+------+-------------+
|  1 | SIMPLE      | nt_accs   | p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20 | index | NULL          | hash     | 7       | NULL |   10 | Using index | 
+----+-------------+-----------+---------------------------------------------------------------------------+-------+---------------+----------+---------+------+------+-------------+
1 row in set (0.00 sec)

5. mysql> EXPLAIN PARTITIONS SELECT nums, count(distinct hash) FROM nt_accs GROUP BY nums;
+----+-------------+-----------+---------------------------------------------------------------------------+-------+---------------+----------+---------+------+------+-----------------------------+
| id | select_type | table     | partitions                                                                | type  | possible_keys | key      | key_len | ref  | rows | Extra                       |
+----+-------------+-----------+---------------------------------------------------------------------------+-------+---------------+----------+---------+------+------+-----------------------------+
|  1 | SIMPLE      | nt_accs   | p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20 | index | NULL          | hash     | 7       | NULL |   10 | Using index; Using filesort | 
+----+-------------+-----------+---------------------------------------------------------------------------+-------+---------------+----------+---------+------+------+-----------------------------+
1 row in set (0.00 sec)

我对第一个和第二个查询非常满意,但我不确定第三个、第四个和第五个的性能。在这一点上我还能做些什么来优化它吗?

【问题讨论】:

    标签: sql mysql database query-optimization


    【解决方案1】:

    唯一性约束会减慢插入速度吗?这与仅创建主键而不是施加唯一约束有何不同?

    是的,索引(MySQL 将唯一约束作为索引实现)会减慢插入速度。
    主键也是如此,这就是为什么需要高插入负载(IE:用于日志记录)的表没有定义主键——以加快插入速度。

    我有很多使用 hash 和 nums 列的 GROUP BY 类型查询。我是继续添加一个转换索引,还是只添加单个索引?

    唯一确定的方法是测试和检查 EXPLAIN 计划。

    更新

    根据提供的解释计划,我看不出对第 3 和第 4 版本的担忧。 MySQL 每个 select_type 只能使用一个索引。第五个版本可能会受益于覆盖索引。

    附录

    只是想确保您知道:

    ALTER TABLE nt_accs ADD UNIQUE(hash, nums, acc);
    

    ...表示三列值的组合将是唯一的。 IE:这些都是有效的,唯一的约束将允许:

    hash  nums  acc
    ----------------
    1     1     1
    1     1     2
    1     2     1
    2     1     1
    

    【讨论】:

    • 感谢您的解释。我知道唯一约束规则。
    • 很抱歉不接受这个答案。我忘了我还有一个问题。我在问题中添加了额外的细节。
    • 所以我认为覆盖索引应该是(nums,hash)。对吗?
    • @Legend:试试看,不过覆盖索引的顺序应该够了——文件排序可能是因为聚合函数的使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多