为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
字段索引 isbn
和 store
添加一个值为generated by
isbn
和store
的字段,该字段设置为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 ...
pricelist
的 PRIMARY KEY
是由 article_id
和 store_id
组成的复合键。
编辑:(已更新以包含评论中的答案)
即使在一百万行上,UPDATE
应该也可以(对于 OK 的特定定义,超过 100 万行可能仍需要一段时间),因为 article_id
和 @987654329 @ 组成 PRIMARY KEY
- 它们将都被编入索引。
您只需要编写查询,使其符合以下内容:
UPDATE pricelist SET price = $fNewPrice
WHERE article_id = $iArticleId
AND store_id =` '$sStoreId'
尽管您可能需要考虑将store
表中的PRIMARY KEY
(store.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_id
和 store_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表选择索引的主要内容,如果未能解决你的问题,请参考以下文章