如何在InnoDB引擎中使用插入延迟,并减少插入语句的连接?


10

我正在开发一个涉及大量数据库写入,大约70%插入和30%读取的应用程序。这个比率还将包括我认为是一次读取和一次写入的更新。通过插入语句,多个客户端通过以下插入语句将数据插入数据库:

$mysqli->prepare("INSERT INTO `track` (user, uniq_name, ad_name, ad_delay_time ) values (?, ?, ?, ?)");

问题是我应该使用insert_delay还是使用mysqli_multi_query机制,因为insert语句使用服务器上的〜100%cpu。我在数据库上使用InnoDB引擎,因此无法进行延迟插入。在服务器上的插入速度为〜36k / hr,读取率为99.89%,我也使用select语句在单个查询中检索了7次数据,该查询在服务器上执行需要150秒。我可以使用哪种技术或机制执行此任务?我的服务器内存为2 GB,我应该扩展内存吗?看看这个问题,任何建议都会感激我。

表的结构:

+-----------------+--------------+------+-----+-------------------+----------------+
| Field           | Type         | Null | Key | Default           | Extra          |
+-----------------+--------------+------+-----+-------------------+----------------+
| id              | int(11)      | NO   | PRI | NULL              | auto_increment |
| user            | varchar(100) | NO   |     | NULL              |                |
| uniq_name       | varchar(200) | NO   |     | NULL              |                |
| ad_name         | varchar(200) | NO   |     | NULL              |                |
| ad_delay_time   | int(11)      | NO   |     | NULL              |                |
| track_time      | timestamp    | NO   | MUL | CURRENT_TIMESTAMP |                |
+-----------------+--------------+------+-----+-------------------+----------------+

我的数据库当前状态,它显示41k次插入(写入),这对于我的数据库来说非常慢。

数据库状态


您可以提供表格的定义吗?(所有列,数据类型和索引)
ypercubeᵀᴹ

SHOW FULL PROCESSLIST当您占用100%的CPU时,您能否简要说明一下?您允许多少连接与这段时间内进行了多少连接?
德里克·唐尼

请运行以下两个查询:SHOW GLOBAL VARIABLES LIKE 'innodb%';SELECT VERSION();然后显示其输出。
RolandoMySQLDBA 2012年

请提供您每秒执行的插入次数。
dabest1

您的代码很容易受到SQL注入的影响。使用准备好的语句和参数化的值。
亚伦·布朗

Answers:


11

由于您撰写的内容多于阅读内容,因此我建议以下内容

体面的InnoDB调整将是关键

缓冲池(由innodb_buffer_pool_size调整大小

由于InnoDB不支持INSERT DELAYED,因此使用大型InnoDB缓冲池是最接近INSERT DELAYED的方法。所有DML(INSERT,UPDATE和DELETE)都将被缓存在InnoDB缓冲池中。写操作的事务性信息将立即写入重做日志(ib_logfile0,ib_logfile1)。通过ibdata1(二级索引的InsertBuffer,双写缓冲区)定期将缓冲区池中发布的写操作从内存刷新到磁盘。缓冲池越大,可以缓存的INSERT数量就越大。在具有8GB或更多RAM的系统中,将75-80%的RAM用作innodb_buffer_pool_size。在RAM很少的系统中,为25%(以容纳OS)。

CAVEAT:您可以将innodb_doublewrite设置为0来加快写入速度,但是有数据完整性的危险。您还可以通过将innodb_flush_method设置为O_DIRECT来加快处理速度,以防止将InnoDB缓存到操作系统。

重做日志(大小为innodb_log_file_size

缺省情况下,重做日志名为ib_logfile0和ib_logfile1,每个重做日志为5MB。该大小应为innodb_buffer_pool_size的25%。如果重做日志已经存在,则在my.cnf中添加新设置,关闭mysql,删除它们,然后重新启动mysql

日志缓冲区(由innodb_log_buffer_size调整大小

在将更改刷新到重做日志之前,日志缓冲区将更改保存在RAM中。默认值为8M。日志缓冲区越大,磁盘I / O越少。对于非常大的事务要小心,因为这可能会使COMMIT的速度降低几毫秒。

访问多个CPU

MySQL 5.5和MySQL 5.1 InnoDB插件具有可让InnoDB存储引擎访问多个CPU的设置。这是您需要设置的选项:

  • innodb_thread_concurrency设置InnoDB可以保持打开状态的并发线程数的上限。通常建议为此设置为(2 X CPU数量)+磁盘数量。去年,我从Percona NYC大会上第一手了解到,您应该将其设置为0,以提醒InnoDB Storage Engine为正在运行的环境找到最佳线程数。
  • innodb_concurrency_tickets设置可以绕过并发检查而不受惩罚的线程数。达到该限制后,线程并发检查再次成为常态。
  • innodb_commit_concurrency设置可以提交的并发事务数。由于默认值为0,因此未设置此选项将允许任意数量的事务同时提交。
  • innodb_thread_sleep_delay设置在重新输入InnoDB队列之前InnoDB线程可以处于休眠状态的毫秒数。默认值为10000(10秒)。
  • innodb_read_io_threads(将其设置为3000)和innodb_write_io_threads(将其设置为7000)(均自MySQL 5.1.38起)为读取和写入分配指定数量的线程。默认值为4,最大为64。将其设置为64。此外,将innodb_io_capacity设置为10000。

升级到MySQL 5.5

如果您有MySQL 5.0,请升级到MySQL 5.5。如果您具有MySQL 5.1.37或更低版​​本,请升级到MySQL 5.5。如果您具有MySQL 5.1.38或更高版本,并且希望保留在MySQL 5.1中,请安装InnoDB插件。这样,您就可以利用InnoDB的所有CPU。


我的服务器内存为2GB,因此根据内存,我将innodb缓冲池设置为500M,并将日志文件的25%设置为缓冲池,还将日志缓冲区设置为64M。但是服务器仍然很忙。我应该升级内存吗?另外我的服务器在32位ubuntu上,因此最大我可以将内存设置为4 GB。
Shashank 2012年

如果服务器仅用于MySQL(没有Apache,没有PHP),则innodb_buffer_pool_size可以达到2GB的75%,即1536M。如果升级到4GB,innodb_buffer_pool_size可以是3G。如您所述,日志文件应为缓冲池的25%。
RolandoMySQLDBA

服务器正在运行apache2,mysql和php,在这种情况下我应该去升级内存还是有什么最佳的解决方案,除了innodb缓冲池?
沙申克

这个家伙不同意您的看法percona.com/blog/2008/11/21/… 很难与Percona争论。
Zenexer 2015年

Rolando-建议您添加5.6和5.7更新的答案。默认值已更改;其他设置可用;等。也许包括Percona和MariaDB以及8.0技巧。
里克·詹姆斯

2

INT(2)仍使用4个字节-也许您是说TINYINT UNSIGNED?

setno中有多少个不同的值?如果太小,则将永远不会使用KEY(setno)。INSERTing必须更新该索引;删除密钥将加快INSERT的速度。

CHAR(10)- flag总是10个字符长吗?在utf8中?也许您可以使用标志VARCHAR(10)CHARACTER SET ascii

批处理您的插入-一次100次将以10倍的速度运行。(超过100表示​​“收益递减”。)

自动提交的价值是什么?您是否将每个INSERT包装在BEGIN ... COMMIT中?innodb_flush_log_at_trx_commit的值是什么?


如果数据是通过外部源(如具有不同值的不同客户端)插入的,如何批量批处理插入...如果我使用的话是否可靠:code插入t_name(col1,col2,col3)值(val1,val2,val3), (val1,val2,val3),(val1,val2,val3),(val1,val2,val3),(val1,val2,val3); code
沙申克

1

设置队列。应用程序将一次写入一个队列中的一行,然后取出行并将其插入数据库,具体取决于自上次插入以来经过的时间的行数。

我已经看到一次批10,000个刀片是最快的,因此您需要进行测试才能找到一个最佳位置。

您可以创建自己的简单队列系统,也可以使用现有的系统。以下是一些示例:HornetQFile :: Queue。这是SE上的文章,列出了其他一些不错的选择:perl,php,python中的消息队列


我同意这种方法-我在一个应用程序上每5秒批处理1500次插入操作,这是不到一秒的时间。mysql似乎在内部实现了某种机制,该机制使得批处理插入真的非常快。
唐·伍尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.