【问题标题】:How to handle large table in MySQL?如何处理 MySQL 中的大表?
【发布时间】:2011-02-23 08:35:29
【问题描述】:

我有一个用于存储项目和有关这些项目的属性的数据库。属性的数量是可扩展的,因此有一个连接表来存储与项目值关联的每个属性。

CREATE TABLE `item_property` (
    `property_id` int(11) NOT NULL,
    `item_id` int(11) NOT NULL,
    `value` double NOT NULL,
    PRIMARY KEY  (`property_id`,`item_id`),
    KEY `item_id` (`item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

这个数据库有两个目标:存储(它具有第一优先级并且必须非常快,我想在几秒钟内执行许多插入(数百次)),检索数据(使用 item_id 和 property_id 选择)(这是一个第二个优先级,它可以更慢但不会太多,因为这会破坏我对数据库的使用)。

目前,此表包含 16 亿个条目,简单的计数最多可能需要 2 分钟...插入速度不够快,无法使用。

我正在使用 Zend_Db 访问我的数据,如果您建议我开发任何 PHP 端元素,我会非常高兴。

【问题讨论】:

  • 这个问题与 php 无关,所以我删除了这个标签
  • 没问题 Jens,你是对的

标签: mysql database optimization


【解决方案1】:

如果由于某些原因您无法使用不同的数据库管理系统或在集群上进行分区的解决方案,那么您仍然可以采取三项主要措施来从根本上提高您的性能(并且它们有效当然也可以与集群结合使用):

  • 设置 MyISAM 存储引擎
  • 使用“LOAD DATA INFILE 文件名 INTO TABLE 表名”
  • 将数据拆分到多个表中

就是这样。仅当您对详细信息感兴趣时才阅读其余部分:)

还在看书吗?好吧,这里是:MyISAM 是基石,因为它是迄今为止最快的引擎。而不是使用常规的 SQL 语句插入数据行,您应该将它们批处理到一个文件中并定期insert that file(根据您的需要经常,但在您的应用程序允许的情况下尽可能少是最好的)。这样,您可以每分钟插入一百万行。

接下来会限制您的是您的键/索引。当这些无法适应您的记忆时(因为它们太大了),您将在插入和查询中体验到巨大的减速。这就是为什么您将数据拆分到多个表中,所有表都具有相同的架构。每张桌子都应该尽可能大,一次加载一张时不要填满你的记忆。确切的大小当然取决于您的机器和索引,但应该在 5 到 5000 万行/表之间。如果您只是测量一个接一个地插入一大堆行所花费的时间,您会发现这一点,寻找它显着减慢的那一刻。当您知道限制后,每次您的最后一张桌子接近该限制时,都可以即时创建一个新表格。

多表解决方案的结果是,当您需要一些数据时,您必须查询所有表而不是只查询一个表,这会稍微减慢您的查询速度(但如果您“仅“有十亿左右的行)。显然,这里也有一些优化。如果有一些基本的东西可以用来分离数据(比如日期、客户或其他东西),你可以使用一些结构化的模式将它分成不同的表,即使不查询表也可以让你知道某些类型的数据在哪里。使用该知识仅查询可能包含请求数据等的表。

如果您需要更多调整,请按照 Eineki 和 oedo 的建议选择 partitioning

此外,您会知道所有这些都不是胡乱猜测:我目前正在对我们自己的数据进行一些类似的可扩展性测试,这种方法对我们来说是个奇迹。我们每天设法插入数千万行,查询大约需要 100 毫秒。

【讨论】:

  • 摇滚这似乎是最完整的一个!我不会尝试“加载数据文件”,我没有任何意愿在 PHP 端重写代码,这将迫使我这样做。我将尝试分区的东西,并将引擎更改为 MyISAM。
  • 从 5.0 更新到 5.1 给了我第一个性能改进。我首先删除了所有外键并使用了 20 个分区。获取所有属性的简单选择(测试 1):从 0.7 秒到 0.37 秒。所有项目的计数(测试 2)从超过一分钟到 11 秒。然后我测试了 200 个分区:测试 1:0,29 s 测试 2:14,86 s 最后我使用了 50 个分区,更改为 MyIsam 并删除了索引:测试 1:0,24 s 测试 2:
【解决方案2】:

要记住的重要一点是,MySQL 的默认安装未配置用于此类繁重的工作。确保您的工作负载有 tuned it

【讨论】:

    【解决方案3】:

    你考虑过partitioning这个选项吗?

    【讨论】:

    • 不,我没有,我认为这可能是一个重要的优化点。
    【解决方案4】:

    第一:一个包含 16 亿个条目的表似乎有点太大了。我在一些负载非常重的系统上工作,即使是跟踪所有操作的日志表也不会多年来变得这么大。所以如果可能的话,想想,如果你能找到一个更优化的存储方法。由于我不知道您的数据库结构,因此无法提供更多建议,但我相信会有足够的优化空间。 16 亿个条目太大了。

    关于性能的一些事情:

    如果您不需要参照完整性检查(这不太可能),您可以切换到 MyISAM 存储引擎。它有点快,但缺乏完整性检查和事务。

    对于其他任何事情,都需要更多信息。

    【讨论】:

    • 就像其他人在这里所说的那样,我已经阅读了 MyISAM 不会让这更快,但我会尝试。
    • 顺便说一句,我没有使用任何 innoDB 功能
    【解决方案5】:

    查看内存缓存,看看它可以应用在哪里。还要研究水平分区以保持表大小/索引更小。

    【讨论】:

    • 我已经使用过 memcache... 它不符合我的需求。我没有要缓存的东西。我长期存储数据,然后经过预处理检索它们。
    【解决方案6】:

    哇,那张桌子好大:)

    如果您需要快速存储,您可以批量插入并使用单个多个 INSERT 语句插入它们。但是,这肯定需要额外的客户端 (php) 代码,抱歉!

    INSERT INTO `table` (`col1`, `col2`) VALUES (1, 2), (3, 4), (5, 6)...
    

    还禁用任何您不需要的索引,因为索引会减慢插入命令的速度。

    或者,您可以查看分区表:linky

    【讨论】:

    • 这个想法不错,但我很喜欢 Zend_Db 来测试它。
    【解决方案7】:

    首先不要使用 InnoDb,因为您似乎不需要它的主要功能而不是 MyISAM(锁定、事务等)。 所以一定要使用 MyISAM,它已经有所作为。 然后,如果这还不够快,请进行一些索引,但您应该已经看到了根本的不同。

    【讨论】:

    • MyISAM 可能比 InnoDB更糟糕,即使纯粹是在速度方面。如果这些更新同时进行,MyISAM 的表级锁定可能会产生很大的负面影响。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-20
    • 1970-01-01
    • 2011-11-16
    • 1970-01-01
    • 2016-04-15
    • 1970-01-01
    • 2010-10-31
    相关资源
    最近更新 更多