执行更新选择时,Mysql超出系统RAM

时间:2014-10-17 01:04:55

标签: mysql

我在mac pro上运行一个mysql服务器,64GB内存,6个内核。我的架构中的表1有3.3亿行。表2有65,000行。 (我还有其他几个表总共大约15亿行,但它们并没有用在我正在尝试的操作中,所以我认为它们不相关)。

我正在尝试做一些我认为是一个相对简单的更新语句(见下文),将表2中的一些数据带入Table1。然而,我有一个糟糕的时间,mysql吹过我的系统ram,迫使我进行交换,并最终冻结整个系统,以便mysql变得反应迟钝,我需要重新启动我的电脑。我的更新声明如下:

UPDATE Table1, Table2 
SET 
  Table1.Column1 = Table2.Column1, 
  Table1.Column2 = Table2.Column2, 
  Table1.Column3 = Table2.Column3, 
  Table1.Column4 = Table2.Column4 
WHERE 
  (Table1.Column5 = Table2.Column5) AND 
  (Table1.Column6 = Table2.Column6) AND 
  (Table1.Column7 = Table2.Column7) AND 
  (Table1.id between 0 AND 5000000);

最终,我想对Table1中的所有3.3亿行执行此更新。我决定将它分成500万行,但是因为

  • (a)我遇到超出锁定大小和
  • 的问题
  • (b)我认为这可能对我吹过公羊的问题有所帮助。

以下是有关情况的更多相关细节:

  • 我已经通过Column5,Column6,Column7(我匹配的值的列)的组合为Table1和Table2创建了索引。
  • 表1有50列,总共约60 GB。
  • 表2有8列,总共3.5 MB。
  • 我知道有些人可能会在这种情况下推荐使用外键,而不是使用table2中的信息更新table1,但是(a)我有足够的磁盘空间而且并不真正关心使用它来达到最高效率( b)这些表中的任何值都不会随着时间的推移而改变。(c)我最关心的是在table1上运行查询的速度,如果需要很长时间才能从table2获取信息到table1,我当然不会这样做。 ; t想要为我在table1上运行的每个查询重复该过程。
  • 为了解决超过最大锁表大小的问题,我尝试增加innodb_buffer_pool_size。我尝试了很多价值观。即使是低至8 GB的东西(即我的计算机和公羊的1/8,而且我这样做时几乎没有其他任何东西),我仍然遇到使用mysqld进程的问题基本上所有ram在系统上可用,然后开始从操作系统中拉出ram分配(即我的kernel_task开始显示为使用30GB的ram,而它通常使用大约2GB)。
  • 最大锁的问题似乎已基本解决;我不再得到这个错误,但也许这只是因为现在我在记忆中崩溃并且在我到达那里之前崩溃了。
  • 我尝试过较小的批量(100万行,100,000行)。这些似乎比500万行批次更好一些,但它们通常仍然有相同的问题,可能只是稍微慢一点开发。并且,性能似乎很糟糕 - 例如,按照我对100,000批量大小的速度,执行此更新大约需要7天。
  • 表格均使用InnoDB
  • 我通常设置SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;虽然我不知道它是否真的有帮助(我是唯一一个以任何方式访问此数据库的用户,所以我并不真正关心锁定,如果可以的话我会完全取消它)< / LI>
  • 我注意到批次运行所需的时间差异很大。例如,在100万行批次中,我会观察时间在45秒到20分钟之间。
  • 当我尝试运行刚刚找到匹配行的内容然后只将两个列值放入新表时,我得到了更多的一致时间(每百万行约2.5分钟)。因此,似乎我的问题可能在某种程度上源于这样的事实,即我更新了表中我正在进行匹配的值,即使我更新的列与我不同的列不同匹配。
  • 我匹配和更新的列只包含INT和CHAR类型,最多不超过7个字符。
  • 我跑了一个CHECK TABLE诊断,它回来了。
  • 总的来说,我非常困惑为什么会这么困难。我一般都是mysql和数据库的新手。由于Table2非常小,我可以使用字典查找在python中完成相同的任务,更快。我想虽然数据库能够更好地处理这个问题,因为处理和更新大数据集是他们的目的。
  • 我使用Mysql工作台对查询进行了一些诊断,并确认没有执行全表扫描。
  • 虽然这看起来确实有些问题。如果系统有64 GB的ram,并且超过两个表组合的整个大小(虽然计算索引大小,这两个表的大小超过64 GB),并且如果操作仅应用于一次有3.3亿行中的500万行,它应该会炸掉这个内存是没有意义的。

因此,我想知道:

  1. 我如何编写此更新语句的语法是多么糟糕和低效,以至于它可以解释可怕的性能和问题?
  2. 除了我应该配置的innodb_buffer_pool_size之外还有某种参数,要么在ram mysql上使用更严格的上限,要么让它更有效地使用资源?
  3. 我是否应该运行其他类型的诊断来尝试检测我的表格,架构等问题?
  4. 什么是合理的&#34;期望这样更新的时间量是多少?

1 个答案:

答案 0 :(得分:0)

因此,在咨询了几位了解此类问题的人之后,我提出了以下解决方案:

  1. 我把innodb_buffer_pool_size降到了4GB,即我整个系统内存的1/16。这最终似乎足以可靠地阻止MySQL通过我的64GB内存。

  2. 我简化了我的索引,以便它们只包含我需要的列,并确保我使用的所有索引都足够小以适应RAM(有足够的空间来备用RAM的其他用途) MySQL也是如此。

  3. 我学会了接受MySQL似乎并不是为特别大的数据集构建的(或者,至少不是在一台机器上,即使是像我这样的相对较大的机器)。因此,我接受了手动分解我的工作往往是必要的,因为显然MySQL的机制并没有做出正确的决定如何自己打破工作的顺序,以便要认真对待像RAM这样的系统资源。

  4. 有时候,当我按照这个或者一般来说,在我适度大的数据集上做工作时,我会使用MySQL来做我的更新和加入。其他时候,我只是将数据分成几块,然后在另一个程序中进行连接或其他此类操作,例如R(通常使用像data.table这样的包,可以相对有效地处理大数据)。

  5. 我还被告知,或者,我可以在Hadoop集群上使用类似Pig of Hive的东西,它应该能够更好地处理这种大小的数据。