我需要一个表来存储一些评分,在此表中,我有一个综合索引(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可能会导致性能问题?我的表结构好还是需要更改?
谢谢
答案 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)
几点:
听起来您只是在使用表的当前唯一性,并将其用作主键。这样可行。由于本地性,自然键在查询方面具有一些优势。 (每个用户的数据存储在同一区域。)
但是,使用您选择的自然主键对性能也有不利影响。
使用非常大的主键会使innodb中的所有其他索引变得非常大,因为主索引包含在每个索引值中。
使用自然主键在搜索中的位置并不像代理键那样快,因为除了较大之外,它每次都不能仅插入表末尾。它必须在该用户的部分中插入并发布等。
此外,您的数据没有按时间搜索的位置。代理键通常对于某些查询是正确的。
使用像您这样的自然键作为主键也可能会很麻烦。如果您想提及特定的投票该怎么办。此外,与许多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 );