为mysql表选择索引

Posted

技术标签:

【中文标题】为mysql表选择索引【英文标题】:Choose an index for mysql table 【发布时间】:2011-10-12 12:45:23 【问题描述】:

桌子

我有一个表格,其中包含 1 000 000 篇文章的价格。这些文章有一个唯一的 ID 号,但该表包含来自多个商店的价格。因此,如果两个商店获得同一篇文章,则唯一 ID 对于该表将不是唯一的。

表结构

表格文章

id INT

价格

存储 VARCHAR(40)

日常使用

除了用户使用 ID 号的查询外,我需要运行每日更新,其中来自 csv 文件的数据插入/更新表中的每篇文章。选择的过程是尝试选择一篇文章,然后执行插入或更新。

问题

考虑到这一点,我应该选择哪个键?

以下是我一直在考虑的一些解决方案:

FULLTEXT 字段索引 isbnstore 添加一个值为generated byisbnstore的字段,该字段设置为PRIMARY键 每个存储一个表并使用isbn 作为PRIMARY

【问题讨论】:

你能把你的表结构贴出来吗? 听起来你需要重组你的表。每个项目应该只有一行。如果它有多个价格,这些价格将反映在一个单独的表中,这可能是商品和商店之间的多对多。 @John OK,然后使用例如autoincremented id 作为那里的键,但是我怎样才能增加性能,因为更新过程需要通过 isbn 浏览 100 万篇文章并更新其中的大部分,你有什么建议? 【参考方案1】:

使用由商店 ID 和文章 ID 组成的复合主键 - 这将为每个商店的每件商品提供唯一的主键,并且您不需要单独的字段(假设store id 和 article id 已经在表中)。

理想情况下,您应该有 3 张桌子...类似于:

article
--------------------------------------------
id | isbn | ... etc ...


store
--------------------------------------------
id | description | ... etc ...


pricelist
--------------------------------------------
article_id | store_id | price | ... etc ...

pricelistPRIMARY KEY 是由 article_idstore_id 组成的复合键。

编辑:(已更新以包含评论中的答案)

即使在一百万行上,UPDATE 应该也可以(对于 OK 的特定定义,超过 100 万行可能仍需要一段时间),因为 article_id 和 @987654329 @ 组成 PRIMARY KEY - 它们将被编入索引。

您只需要编写查询,使其符合以下内容:

UPDATE pricelist SET price = $fNewPrice 
WHERE article_id = $iArticleId 
AND store_id =` '$sStoreId'

尽管您可能需要考虑将store 表中的PRIMARY KEYstore.id - 因此还有pricelist 表中的pricelist.store_id)转换为无符号整数或类似 CHAR(30)

虽然 VARCHAR 在磁盘空间方面效率更高,但它有几个缺点:

1:mysql 不太热衷于更新 VARCHAR 值,它会使索引有点膨胀,因此您可能需要偶尔在其上运行 OPTIMIZE TABLE(我在 order_header 上找到了这个 em> 之前的表)。

2:任何具有非固定长度字段(例如 VARCHAR)的 (MyISAM) 表都必须具有 DYNAMIC 行格式,当它使用时效率会稍低一些来查询它 - 在这个 SO 帖子中有更多关于它的信息:MySQL Row Format: Difference between fixed and dynamic?

【讨论】:

因为我需要在 +1M 帖子上运行更新,例如价格表。然后我应该检查 article_id 和 store_id 的复合键吗?这会产生任何性能问题吗?我的测试是它可以很好地使用 PRIMARY 键进行搜索,但使用非键进行搜索要求太高。 应该没问题,因为 article_idstore_id 都将被编入索引(因为它们构成主键) - 您只需要编写查询,使其符合要求的UPDATE pricelist SET price = $fNewPrice WHERE article_id = $iArticleId AND store_id = '$sStoreId'——我会更新答案,因为有几个附带条件:)【参考方案2】:

您的索引应该与您的查询保持一致。当然,在文章表上应该有一个使用 STORE 和 ID 的主键 - 但声明它们的顺序会影响性能 - 取决于相关表中的数据和应用的查询。实际上,最简单的解决方案可能是 PRIMARY KEY(STORE, ID) UNIQUE KEY(ID, STORE) 以及这两个字段的外键约束。

即由于将此表称为“文章”毫无意义,因此我将使用与 CD001 相同的架构:

CREATE TABLE pricelist (
    id INT NOT NULL ,
    price INT,
    store VARCHAR(40) NOT NULL
    PRIMARY KEY(store,id),
    UNIQUE KEY rlookup (id, store)
    CONSTRAINT id FOREIGN KEY articles.id,
    CONSRAINT store FOREIGN KEY store.name
);

这还需要使用名称在商店中拥有一个主键。

基于单列检查键和基于 2 列检查键之间的差异可以忽略不计 - 规范化您的数据库属性将为您节省很多痛苦。

【讨论】:

以上是关于为mysql表选择索引的主要内容,如果未能解决你的问题,请参考以下文章

MySql 没有为少数查询选择正确的索引

MySQL索引选择及添加原则

MySQL 索引优化器选择索引的规则是啥?

单表扫描,MySQL索引选择不正确 并 详细解析OPTIMIZER_TRACE格式

10 MySQL索引选择与使用

MYSQL怎样设置字段为不可重复