【问题标题】:MySQL indexes - how to boost performace?MySQL 索引 - 如何提高性能?
【发布时间】:2011-09-17 08:17:21
【问题描述】:

我正在尝试提高现有 MySQL 数据库的性能。

这是一个关于餐馆的数据库,有两个相关的表:

网站的所有实体都有一个表格,每个实体都有一个唯一的 id, 实体几乎可以是任何东西,它可以是餐厅、用户和许多其他事物。 实体类型有好几种,对于餐馆,它们的实体类型是“对象”。

我还要说,数据库的这种结构几乎是存在的 所以我不想做大的改变,我不会删除所有实体的表 例如。 (数据库本身没有数据,但是 PHP 引擎是内置的,所以它会 很难对结构进行大的改动)。

还有一个只用于对象的表,有几种类型 该数据库中的对象,但特别是餐馆 搜索很多,因为这是网站的主题, 餐馆有几个字段:国家、城市、名称、流派。 同一个城市和国家不可能有两家同名的餐厅, (例如可以有两家同名但在不同城市的餐厅 同一个国家或两个同名但在不同国家的城市)

所以从这个事实来看,我想我应该为国家、城市和名称列创建一个唯一的三列索引。

另外我想说的是,URL也是以www.domain.com/Country/City/Restuarant-Name的形式构建的,所以country-city-name的组合应该是快速获取和这种类型的查询会发生很多事情。

但也会有很多其他类型的查询,例如:搜索名称 餐厅(使用 LIKE 查询,因为搜索的名称可以是一部分 全名)在某个城市,或者在某个国家。 搜索某个国家和城市中某种类型的所有餐厅。 以及几乎所有可能的组合。

最常用的查询可能是 (a) 在某个城市搜索餐厅名称 和国家(这将与键入 URL 时使用的查询相同,但将使用 LIKE), (b) 在某个城市和国家搜索某种类型的餐馆。 最后(c)在全球范围内搜索餐厅名称(在整个数据库中,不指定城市和国家)

此表(对象表)当前具有 PRIMARY KEY,即对象的 ID, 该ID也被大量使用,最佳做法如下?:

  1. 根据国家、城市、名称创建一个三列的唯一索引
  2. 从名称中创建另一个(非唯一)索引(所以我写了一个 c 类型的查询 以上将快速执行)
  3. 可能会制作某种子表,其中仅包含对象中的餐馆 表,因此将查询此子表。 (这不太重要,因为如果我决定 为了做出重大改变,我可能会将餐厅与对象的其余部分分开 开始)

我非常感谢任何帮助,因为我已经尝试了很长时间来决定这个问题。

p.s 在对象表中的一些对象不会有任何类型或任何国家或城市, 所以它们将保持为 NULL,我知道 UNIQUE KEY 中允许使用 NULL 值,但它会 对性能有影响吗?

感谢任何愿意阅读这个长问题的人:)

【问题讨论】:

标签: mysql indexing multiple-columns


【解决方案1】:

您可以随心所欲地思考和计划,但在您尝试、基准测试和比较您的选择之前,您无法确定什么是最好的。也就是说,听起来您肯定走在正确的轨道上。

复合键
您的“country-city-name”复合键似乎是最有用的顺序,因为它是从最广泛到最窄的选择标准排序的。我确定您是故意这样做的,因为复合键的值只能从左到右使用。因为 name 在该索引中没有排在第一位,所以您需要一个单独的键来仅用于 name,正如您所指出的那样。

索引值 NULL
根据imysql.cn 的说法,“在索引中允许 NULL 值确实不会影响性能。”这只是简单地陈述为没有数据或参考的旁白,所以我不知道他们如何/是否证明了这一点。

拆分表格
如果餐厅记录中混入了很多其他数据,当然,这可能会减慢速度。如果您将shard 表转换为结构相同的“餐厅”和“其他”表,您仍然可以在必要时使用简单的 UNION 轻松查询它们的组合数据。除非您对预期的数据/减速有所了解,否则我宁愿避免对表进行分片,除非必要,至少为了简单/统一起见。

是否存在当前索引无法考虑的可预见查询,例如没有国家/地区的城市?如果是这样,请务必适当索引以涵盖所有可预见的情况。你没有提到它,但我想你也会有一个关于 genre 的索引。


最终,您需要生成大量测试数据并进行尝试。(确定您最终可以预期多少数据,并生成至少三倍的测试数据数据以使系统步入正轨。)根据您的描述,设计听起来不错,但测试可能会发现意想不到的问题,您将从不同索引中受益的地方等。发现任何问题后,您会有一个特定的目标要完成,而不是简单地考虑所有假设场景。

【讨论】:

  • 非常感谢,我想说的还有一个想法是我还会有一个评级列用于对餐厅进行排序,这对答案有影响吗?我假设不能有多个索引,也许只是添加评级并使其成为四列索引? (国家、城市、名称、评级)
  • @fiftyeight 你的意思是“不能超过一个”主键?因为当然可以有尽可能多的索引。我认为您不会希望将 rating 包含在该唯一复合索引中。它不用于识别记录。只需在 rating 列上放置一个非唯一索引。
  • @fiftyeight 所以看起来你将有四个索引:1)ID 上的主键,2)“country-city-name”上的唯一复合索引,3)常规索引name,4) rating 上的常规索引。应该这样做,除非您发现某些查询由于某种原因不能使用它们。如果您确实发现了这一点,那么这就是 SO 真正可以提供帮助的地方。 :-)
  • Wiseguy 感谢所有的帮助,我真的表达得很糟糕。我的意思是我假设 MySQL 不能为同一个查询使用多个索引,据我了解,它根据查询决定使用哪个索引,而不是仅使用该索引。假设用户搜索英国伦敦的所有餐厅,MySQL 将能够使用 Country-City-Name 索引
  • 但假设查询显示“SORT BY index LIMIT 10”,因为我想显示 10 个结果,并且只显示评分最高的 10 个餐厅。因此,如果仅对评级有一个索引,我怀疑它不会有帮助,但如果该索引是 Country-City-Name-Rating,我认为它将帮助 MySQL 找到评级最高的餐厅,因为它至少可以使用该索引找到国家和城市。这对我来说似乎是合乎逻辑的,但也许我错过了一些东西。我认为我永远不需要单独使用评级。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-15
  • 2014-11-25
相关资源
最近更新 更多