【问题标题】:is there a way to throttle the indexing of Mysql tables so overall performance is not impacted?有没有办法限制 Mysql 表的索引,所以整体性能不受影响?
【发布时间】:2011-08-22 01:59:45
【问题描述】:

我需要将一个大型数据集加载到生产数据库中。

需要分别上传 15 个文件并插入到表格中。 每个大约 500 Mb

我有两个需要索引的 ID 列。 如果我加载带有索引的文件,上传大约需要 3 个小时。 如果我删除索引,加载数据本地 infile,然后重新添加索引,整个操作大约需要 30 分钟。

问题是,数据库响应能力在为新导入的数据编制索引时受到很大影响。有没有办法让索引以“低优先级”运行,以便其他查询仍然获得 95-100% 的速度,并且索引类型在后台运行?

我正在使用 Amazon RDS,因此我无法选择仅在不同的服务器上加载然后复制表格文件。

为此添加赏金,因为我仍然想看看是否有办法在对特定框进行索引时获得良好的性能。

【问题讨论】:

  • 请为正在加载的表运行 SHOW CREATE TABLE tblname\G。我们需要看看这个表是什么存储引擎。请向我们展示 /etc/my.cnf 文件。
  • 我目前正在使用myisam,但我也尝试过innodb。我愿意使用任何一个。同样,最大的问题是试图限制索引,而不是试图提高性能。
  • 不清楚您执行此操作的频率,但您似乎暗示这是一次性的。出于好奇,大约 30 分钟的停机时间是什么问题?不能在低使用时段(夜间/午餐时间)执行吗?
  • 数据加载需要每周至少发生一次,但有时每天一次。我不在乎它们是否需要 6 个小时,我只是想限制它们,这样它们就不会影响其余的查询。

标签: mysql indexing throttling


【解决方案1】:

嗯,我从来没有找到节流的方法,但我确实找到了缓解问题的方法。 该解决方案对我的问题来说是独一无二的,但我会发布它以防其他人发现它有用。

我写了一个名为CautiousIndexer 的类。

  1. 首先我存储了create table 语句来重新创建没有索引的表结构。我存储了一组读取的从数据库,循环遍历它们,将未索引数据的表重命名为prevent_indexing_($name)
  2. 然后我只在从属服务器上运行了 create table 语句。这有效地将数据移出索引语句的方式,这些语句将发生在主服务器上。
  3. 然后我对主服务器运行索引查询。由于新创建的表是空的,读取从属服务器在主服务器建立索引时没有性能影响。
  4. 当主服务器完成索引时,我将 1 个从服务器从生产轮换中取出,删除了空表,将满表移回原位,然后在生产外的从服务器上对表进行索引。
  5. 完成后,我将其重新投入生产,并在其余从站上重复从站索引过程。
  6. 当所有从站都建立索引后,我将表投入生产。

这在效率方面仍然很好,但是在主服务器上的索引期间写入性能下降得令人无法接受。仍在寻找一种通过限制进行索引的方法。

【讨论】:

  • 这个解决方案有帮助,但我发现它还不够。某些查询仍然需要直接访问主数据库以进行事务处理,并且在索引期间它们的速度令人无法接受。
【解决方案2】:

一个很好的解决方案是执行滚动更新的脚本。您将以非复制方式将索引应用于每个从站。粗略的说明:

for host in $hosts
do
    mysql -h $host -e "STOP SLAVE;\
      SET sql_log_bin=0;\
      FLUSH TABLE t;\
      ALTER TABLE t ADD INDEX a (b,c);\
      SET sql_log_bin=1;\
      START SLAVE;"
done

通过关闭复制,应减少磁盘活动量并提高索引操作的速度。如果您对从属服务器有数据库延迟要求,您可能希望完全解除从属服务器的池化,并包括在从属服务器恢复零秒延迟时重新池化该从属服务器的逻辑。

【讨论】:

  • 我目前几乎完全做到了这一点,但这仍然不够。主数据索引导致 0.5% 的需要主数据的查询太慢。我需要一种方法来限制索引,以便它可以在索引的同时仍然响应其他表。
  • Zak,您有一个购买更多设备的绝佳商业案例!另一种可能性是在从属上对表进行索引,将其复制到主控,然后将其重命名为SET sql_log_bin=0; flush table t; rename t to dugout_t, t_atbat to t; SET sql_log_bin=1;
  • 我有点担心 22。我转移到 RDS 以避免系统管理成本,但每机器小时支付更多费用。但是,RDS 不允许您移动索引或表,因为您无法直接访问文件系统。如果我在 RDS 中增加我的数据库大小,我将失去所有的系统管理员成本节省,因为我正在使用的多可用区数据库真的开始变得昂贵!
  • 这也可以通过政策和客户信息来解决。您的站点是否与客户签订了特定的 SLA 协议?考虑在您的客户登录页面上创建“站点维护通知”,警告他们降级或服务中断,然后在您警告他们的日期和时间做讨厌的事情。
【解决方案3】:

这不是您正在寻找的确切解决方案,但您可以在此单个框中绑定 a second mysqld instance as a slave 并根据需要将 SELECT 查询重定向到它。 MySQL Proxy 可以帮助您在不重写客户端应用程序的情况下完成此操作。

您还可以从FriendFeed usage of MySQL 收集一些想法。它们将实际索引存储在其他表中并用于搜索。如果您将数据副本存储在其他表中,甚至在其他服务器上并在那里运行索引,您将能够尽快全速访问主数据,并在以后使用其他服务器获得更快的查询。

这就像您在从属服务器上添加索引以进行搜索类型查询,并在主服务器上仅运行主键查找。

【讨论】:

  • 如果我不需要处理交易也可以。我需要主人起来,这样我才能写信给它。在索引期间写入速度太慢(在其他表上)。
  • 我添加了一条关于他们在 FriendFeed 上实际做了什么的注释。
【解决方案4】:

一个以前没有尝试过的想法也不是关于索引限制,如果你制作一个备份表并用你提到的方式更新它有更短的时间跨度,而不是转换/重命名表。我鼓励写下我的想法,因为你需要知道一种方法。

【讨论】:

    【解决方案5】:

    您可以在插入时禁用任何非唯一索引,并在完成后重新启用它们。看看禁用键/启用键。但它仅适用于非唯一索引。

    如果您使用多值插入语句(insert into table(...) values(...),(...),(...)...

    p>

    顺便说一下,load data infile似乎是在mysql中插入大量数据的最快方法。

    【讨论】:

    • 是的,我可以在禁用键的情况下在大约 5 分钟内加载所有数据。但是当我启用键时 .. 会发生索引!这就是扼杀我的数据库性能的原因。
    【解决方案6】:

    您是否尝试过提高导入的索引设置?这可以显着提高导入性能。 sort_buffer_size 适用于任何表类型,myisam_sort_buffer_size 适用于 MyISAM 表。 innodb_buffer_pool_size 是 Innodb 的“密钥缓存”。根据您的表格类型,为导入添加这些内容。您要做的是在创建索引期间避免文件排序。

    您可以将导入/索引时间缩短到 10-15 分钟或更短。不是节流,但会显着缩短影响期。

    或者,如果您使用的是 MyISAM 表,也许可以选择 MERGE 表?创建一个新表,执行导入,然后将新表添加到 MERGE 表中。导入期间不会对数据库产生影响。除了服务器执行任务。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-02
      • 1970-01-01
      • 1970-01-01
      • 2011-05-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多