具有复合索引但不具有主键的MySQL表

时间:2019-07-27 14:11:40

标签: mysql sql

我需要一个表来存储一些评分,在此表中,我有一个综合索引(user_id,post_id)和其他列,以标识不同的评分系统。

user_id - bigint
post_id - bigint
type - varchar
...

Composite Index (user_id, post_id)

在此表中,我没有主键,因为主键必须是唯一的,而INDEX不必是唯一的,在我的情况下,唯一性是个问题。

例如,我可以拥有

INSERT INTO tbl_rate
    (user_id,post_id,type)
VALUES
    (24,1234,'like'),
    (24,1234,'love'),
    (24,1234,'other');

缺少PRIMARY KEY可能会导致性能问题?我的表结构好还是需要更改?

谢谢

2 个答案:

答案 0 :(得分:1)

  

缺少PRIMARY KEY可能会导致性能问题?

在InnoDB中可以肯定,因为InnoDB将使用算法来创建自己的“ ROWID”, dict0boot.ic

中定义了
Returns a new row id.
@return the new id */
UNIV_INLINE
row_id_t
dict_sys_get_new_row_id(void)
/*=========================*/
{
    row_id_t    id;

    mutex_enter(&(dict_sys->mutex)); 

    id = dict_sys->row_id;

    if (0 == (id % DICT_HDR_ROW_ID_WRITE_MARGIN)) {

        dict_hdr_flush_row_id();
    }

    dict_sys->row_id++;

    mutex_exit(&(dict_sys->mutex));

    return(id);
}

该代码中的主要问题是mutex_enter(&(dict_sys->mutex));,如果一个线程已经在运行此代码,则该代码将阻止其他线程访问。 这意味着它将与MyISAM一样使用表锁。

此外,模运算符(%)是CPU重指令。
但是,如果DICT_HDR_ROW_ID_WRITE_MARGIN为2的幂,则可以优化C / C ++编译器(和/或配置选项)。
(0 == (id & (DICT_HDR_ROW_ID_WRITE_MARGIN - 1)))一样,位屏蔽要快得多,我相信DICT_HDR_ROW_ID_WRITE_MARGIN确实有一个2的幂的数字

答案 1 :(得分:1)

几点:

听起来您只是在使用表的当前唯一性,并将其用作主键。这样可行。由于本地性,自然键在查询方面具有一些优势。 (每个用户的数据存储在同一区域。)

  1. 但是,使用您选择的自然主键对性能也有不利影响。

  2. 使用非常大的主键会使innodb中的所有其他索引变得非常大,因为主索引包含在每个索引值中。

  3. 使用自然主键在搜索中的位置并不像代理键那样快,因为除了较大之外,它每次都不能仅插入表末尾。它必须在该用户的部分中插入并发布等。

  4. 此外,您的数据没有按时间搜索的位置。代理键通常对于某些查询是正确的。

  5. 使用像您这样的自然键作为主键也可能会很麻烦。如果您想提及特定的投票该怎么办。此外,与许多ORM一起使用也有点困难。

与依赖innodb的内部主键相比,您可以创建自己的代理键,因为您将能够使用它进行更新和查找。

ALTER TABLE tbl_rate ADD id INT UNSIGNED NOT NULL AUTO_INCREMENT, ADD PRIMARY KEY(id);

但是,如果您确实创建了代理主键,那么我还将使您的键成为唯一键。相同的成本,但可以确保正确性。

ALTER TABLE tbl_rate ADD KEY ( user_id, post_id, type );