【问题标题】:Too many columns to index - use mySQL Partitions?要索引的列太多 - 使用 mySQL 分区?
【发布时间】:2010-12-13 13:19:15
【问题描述】:

我们有一个包含 20 多列的表的应用程序,这些列都是可搜索的。为所有这些列建立索引会使写查询非常慢;并且任何真正有用的索引通常都必须跨越多个列,从而增加所需的索引数量。

但是,对于 95% 的这些搜索,只需要搜索这些行中的一小部分,而且数量相当少 - 例如 50,000 行。

所以,我们考虑使用 mySQL 分区表 - 有一个基本上是 isActive 的列,这是我们划分两个分区的依据。大多数搜索查询将使用isActive=1 运行。然后,大多数查询将针对 50,000 行的小分区运行,并且无需其他索引即可快速运行。

唯一的问题是isActive=1 不固定的行;即它不是基于行的日期或任何类似的固定;我们将需要根据该行中数据的使用情况更新isActive。据我了解,这没问题;在 UPDATE 查询期间,数据只会从一个分区移动到另一个分区。

我们在id 上确实有一个PK 用于该行;我不确定这是否有问题;该手册似乎建议分区必须基于任何主键。这对我们来说将是一个巨大的问题,因为主键 ID 没有根据行是否为 isActive

【问题讨论】:

  • 如果 3NF 是所有性能问题的解决方案,那么没有人会创建星型模式。

标签: database-design mysql partitioning database-partitioning


【解决方案1】:

我不是 MySQL 专家。我的重点是 Oracle,但多年来我一直在使用分区,我发现您建议的使用非常合适,但不在分区的主流理解范围内。

低基数列的索引

暂时搁置索引合并。假设您的活动行有些分散,并且与非活动行数的比例为 1:20。假设您的页面大小为 8Kb,每块大约有 20 行。如果您获得非常均匀的 isactive 记录分布,则每个块几乎有 1 个。与使用索引查找相同的行相比,读取表中的每个块/页的全表扫描要快得多、快得多。

假设它们是集中的,而不是均匀分散的。即使它们集中在 20% 甚至 10% 的页面中,即使在这些情况下,全表扫描也可以执行索引。

所以现在包括索引合并。如果在您扫描 ISactive 的索引之后,您没有访问该表,而是将这些结果连接到另一个索引的结果,并且最终结果集将产生读取,例如,少于 5% 的块。那么是的,isactive 和索引合并上的索引可能是一个解决方案。

这里需要注意的是,在 MySQL 中索引连接的实现有很多限制。确保这适用于您的情况。但是您说您还有另外 20 个字段可以搜索。因此,如果您不为所有这些索引编制索引,以便有第二个索引可将 IsActive 索引加入其中,则您将不会使用索引合并/加入。

对低基数列进行分区

现在,如果您在该列上进行分区,您将拥有 5% 的 IsActive = True 块,并且它们将被密集填充。完整的分区扫描将快速生成活动记录列表,并允许将所有其他谓词用作过滤器而不是索引查找。

但是那个标志改变了,对吧。

在 Oracle 中,我们有一个命令允许我们启用行迁移。这意味着,当 Is_Active 从 True 更改为 False 时,移动该行所在的分区。这非常昂贵,但仅比索引该列而不是按其分区时发生的索引维护多一点。在一个分区的例子中。 Oracle 首先通过更新更改行,然后执行删除,然后执行插入。如果您为该列建立索引,您将更新该行,然后删除 TRUE 的索引条目,然后创建 False 的索引条目。

如果 MySQL 没有行迁移,那么您必须对 crud 包进行编程才能做到这一点。 UPDATE_ROW_ISACTIVE(pk IN number) 过程

关于 Konerak 的回答

虽然我同意并行访问是分区的一种用途,但它并不是唯一的。但是如果你点击他提供的链接,页面最底部的用户评论是:

请注意您的表上的选择性索引较低。如果 Index_Merge 优化与 intersect() 算法一起使用,复杂的 AND/OR WHERE 子句肯定会使您的查询非常缓慢。

这似乎与您的情况有关,因此您可以在 FWIW 上接受该评论。

【讨论】:

  • 在我的公司,我们经常使用这种模式。事实上,我们使用的列具有确切的名称。我们在 8 小时内使用非常大容量的系统、数亿行和 100,000 笔交易来做到这一点。
  • 我非常感谢这里的回复,因为它让我们有信心继续尝试和基准测试。刚刚解决了 mySQL 的 PK 问题以及我们如何处理移动行。
  • 只需创建一个更新过程(您应该已经拥有它,对吗?)并让它分叉该过程,如果 IsActive 正在改变。
【解决方案2】:

如果您要索引那么多“列”,您可能需要重新考虑您的数据结构。例如,将每列改为行/记录。然后有一个“组 ID”将各个记录链接在一起,并有一个“名称”字段来指示它是什么数据。然后,您的所有数据只需要 1 个索引。

这种名称/值对设置现在实际上相当普遍,并且是某些 noSQL 数据库所基于的。这是您可能想要研究的其他内容。像 MongoDB 这样的东西非常适合索引“所有”数据。

【讨论】:

    【解决方案3】:

    您不需要为此进行分区 - 只需在您的 isActive 列上添加一个索引就足够了。请注意,MySQL 可以使用Index Merge 操作来使用这两个索引。

    当允许并行执行搜索时,分区将很有用:例如,如果您按日期分区,则可以同时搜索 5 个分区以查找跨越 5 年的结果。

    【讨论】:

      【解决方案4】:

      您对“表”和“数据库”的描述是缺乏规范化的典型症状。具有 20 个可搜索列的“表”不是 3NF,甚至可能不是 1NF。最好的建议是回到第一原则,并规范化数据,这将导致更窄的表,并且每个表的行数也更少,但可以肯定的是,mote 表。然而,结果也有更少的索引,每张表,和整体。

      还有一个更快的数据库。宽泛的“表格”对于各个级别的性能来说都是一场灾难。

      分区不适用于此处,它们不会缓解您的问题。

      id PK 是一个附加索引,一个代理项,一个替代(但不是替代)真正的主键。如果您使用关系建模技术,则可以消除这种情况,至少可以减少到 19 个可搜索索引。 “表”上的任何严肃工作都将以真正的 PK 为中心,而不是代理,例如,正如您从分区限制中看到的那样。

      如果您想讨论它,请发布您的“表”以及每个连接的“表”的 DDL。

      回复评论

      该表最好被认为是“电子邮件”,但有很多额外的字段(类别/部门/优先级/工作流程/所有者)都已正确规范化。还有一系列其他变量,包括相当多的时间戳。

      这就是平面文件的定义,在 0NF。除非您使用“规范化”的一些不成文定义,否则根据您自己的描述,它根本没有规范化。这是开始任何规范化之前的文章。

      • 毫无疑问,索引也是宽泛的,以便对查询有用。

      • 您可能还没有意识到,该文件中存在大量数据重复,以及更新异常(当您更新一行中的列时,您必须更新其他行中的重复值),这使您的应用程序变得不必要地复杂。

      您需要了解所有关系 DBMS 供应商编写的关系 数据库引擎都经过优化以处理关系 数据库。这意味着它们针对规范化而不是非规范化或非规范化结构进行了优化。

      我不会卷入学术争论,SO 是问答网站,而不是辩论网站。根据要求,发布文件的 DDL,以及所有连接的文件,我们绝对可以 (a) 给它一些速度并 (b) 避免 20 多个索引(这是该情况的另一个常见症状)。这将处理特定的现实世界问题并解决它,避免争论。

      其次,你似乎把角色弄混了。是你,有问题,在 SO 上发布问题,是我解决了数百个性能问题,回答。根据定义,解决方案在您的域之外,否则您会解决它,因此您不会发布问题;所以当你告诉我如何解决你的问题时它不起作用。这将把我束缚在与你相同的限制中,从而确保我不会解决问题。

      同样根据我们的测试,有很多表要加入我们需要包含在 WHERE 子句中的表只会使查询变慢。

      实际上,我以调优数据库为生,我进行了数百次测试,证明连接许多更小的表更快。研究编码器的测试和编码能力会很有趣,但这会引发争论,所以我们不要这样做;让我们坚持这个问题。如果您想要 (a) 认真测试的示例 (b) 证明我在受到挑战之前所说的话,这里只是 one example 完整记录并受到甲骨文世界中坚挺者的审查和相应测试。

      您可能也对这个question/answer 感兴趣,它扼杀了您正在接近的同一场辩论。

      加入无需任何费用。您加入的文件;以及两边加入的记录数;索引的有用性,这就是成本所在。如果它是另一个非规范化文件(胖、宽、许多可选列),肯定会很慢。

      无论如何,如果您真的有兴趣解决您发布的问题,请发布您的所有 DDL,我们可以为您提供更快的解决方案。如果您想要的只是一个是/否答案重新分区(并且不解决导致问题的问题),那也没关系;你已经有了。

      【讨论】:

      • 事实并非如此。该表最好被认为是“电子邮件”,但有很多额外的字段(类别/部门/优先级/工作流程/所有者),这些字段都已正确规范化。还有一系列其他变量,包括很多时间戳。同样从我们的测试来看,有很多表要加入我们需要包含在 WHERE 子句中的表只会使查询变慢。
      • @Christopher Padfield。在我的帖子中回复。
      • 感谢您的帮助;但这只是来自我们的测试(请注意我们使用的是 mySQL 而不是 Oracle)。需要明确的是,我提到的所有字段都是具有其他表主键的 ID(时间戳除外);它们有很多,因为有很多数据要存储。我还不能发布整个数据结构,但可能很快我会在这里更新。尽管我们的测试已经在几百万行上显示,超过几个连接的性能是不可接受的;并且限制搜索数据量的解决方案可能会奏效。
      • 您还可以在这个问题中看到我们在使用 JOINS 时遇到的一些问题:stackoverflow.com/questions/3101450/… - 赞成的回复是最有用的;答案需要一段时间才能复制问题,但正如他们所说“确实,进行连接是有一些成本的。它如此昂贵有点令人惊讶。但如果你使用索引,这可以得到缓解。“好吧,很遗憾,我们无法为所有内容编制索引。
      • @Christopher Padfield。你想解决你的问题,还是想谈谈它?我有 34 年为 DBMS 供应商和客户设计和调优数据库的经验,这是我做出陈述的基础。我对“他们”所说的话没有任何评论。大多数“他们”只读过 wiki,其余的则有使用一两个数据库的经验。当您发布所有 DDL 时,解决方案就开始了。
      猜你喜欢
      • 2011-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      • 2019-01-24
      • 2015-02-11
      • 2017-02-21
      相关资源
      最近更新 更多