35

这是一个非常简单的问题。将数据插入表中通常工作正常,除了插入查询需要几秒钟的几次。(我不是要批量插入数据。)所以我为插入过程设置了一个模拟,以找出为什么插入查询有时需要超过 2 秒才能运行。Joshua 建议索引文件可能正在调整;我删除了 id (主键字段),但延迟仍然发生。

我有一个 MyISAM 表:(daniel_test_insert这个表开始完全是空的):

create table if not exists daniel_test_insert ( 
    id int unsigned auto_increment not null, 
    value_str varchar(255) not null default '', 
    value_int int unsigned default 0 not null, 
    primary key (id) 
)

我将数据插入其中,有时插入查询需要超过 2 秒才能运行。 此表上没有读取- 仅由单线程程序串行写入。

我将完全相同的查询运行了 100,000 次,以找出查询有时需要很长时间的原因。到目前为止,这似乎是一个随机事件。

例如,这个查询花费了 4.194 秒(插入的时间很长):

Query: INSERT INTO daniel_test_insert SET value_int=12345, value_str='afjdaldjsf aljsdfl ajsdfljadfjalsdj fajd as f' - ran for 4.194 seconds
status               | duration | cpu_user  | cpu_system | context_voluntary | context_involuntary | page_faults_minor
starting             | 0.000042 | 0.000000  | 0.000000   | 0                 | 0                   | 0                
checking permissions | 0.000024 | 0.000000  | 0.000000   | 0                 | 0                   | 0                
Opening tables       | 0.000024 | 0.001000  | 0.000000   | 0                 | 0                   | 0                
System lock          | 0.000022 | 0.000000  | 0.000000   | 0                 | 0                   | 0                
Table lock           | 0.000020 | 0.000000  | 0.000000   | 0                 | 0                   | 0                
init                 | 0.000029 | 0.000000  | 0.000000   | 1                 | 0                   | 0                
update               | 4.067331 | 12.151152 | 5.298194   | 204894            | 18806               | 477995           
end                  | 0.000094 | 0.000000  | 0.000000   | 8                 | 0                   | 0                
query end            | 0.000033 | 0.000000  | 0.000000   | 1                 | 0                   | 0                
freeing items        | 0.000030 | 0.000000  | 0.000000   | 1                 | 0                   | 0                
closing tables       | 0.125736 | 0.278958  | 0.072989   | 4294              | 604                 | 2301             
logging slow query   | 0.000099 | 0.000000  | 0.000000   | 1                 | 0                   | 0                
logging slow query   | 0.000102 | 0.000000  | 0.000000   | 7                 | 0                   | 0                
cleaning up          | 0.000035 | 0.000000  | 0.000000   | 7                 | 0                   | 0

(这是 SHOW PROFILE 命令的缩写版本,我把所有的列都扔掉了。)

现在更新有大量的上下文切换和轻微的页面错误。Opened_Tables 在此数据库上每 10 秒增加约 1 个(未用完 table_cache 空间)

统计:

  • MySQL 5.0.89

  • 硬件:32 Gigs 内存 / 8 核 @ 2.66GHz;突袭 10 个 SCSI 硬盘(SCSI II ???)

  • 我已经询问了硬盘驱动器和 RAID 控制器:没有报告错误。CPU 大约有 50% 空闲。

  • iostat -x 5(报告硬盘利用率低于 10%) top 报告负载平均约 10 1 分钟(我们的数据库机器正常)

  • 交换空间已使用 156k(32 gigs ram)

我不知道是什么导致了这种性能滞后。这不会发生在我们的低负载从属设备上,只会发生在我们的高负载主机上。这也发生在内存和 innodb 表中。有没有人有什么建议?(这是一个生产系统,所以没有什么异国情调!)

4

11 回答 11

22

我在我的系统上注意到了同样的现象。通常需要一毫秒的查询会突然需要 1-2 秒。我的所有案例都是简单的单表 INSERT/UPDATE/REPLACE 语句 --- 不在任何 SELECT 上。没有明显的负载、锁定或螺纹堆积。

我曾怀疑这是由于清除了脏页、刷新磁盘更改或某些隐藏的互斥锁,但我还没有缩小范围。

也排除了

  • 服务器负载——与高负载无关
  • 引擎——发生在 InnoDB/MyISAM/Memory
  • MySQL 查询缓存——无论是打开还是关闭都会发生
  • 日志轮换——事件中没有相关性

我在这一点上唯一的其他观察来自我在多台机器上运行相同的数据库这一事实。我有一个繁重的读取应用程序,所以我正在使用一个具有复制功能的环境——大部分负载都在从属设备上。我注意到,即使主服务器上的负载很小,这种现象也更多地发生在那里。即使我没有看到锁定问题,也许是 Innodb/Mysql 在(线程)并发方面遇到问题?回想一下,从站上的更新将是单线程的。

MySQL 版本 5.1.48

更新

我想我对我的案子的问题有线索。在我的一些服务器上,我注意到这种现象比其他服务器更多。看到不同服务器之间有什么不同,并进行了调整,我被引导到MySQL innodb 系统变量 innodb_flush_log_at_trx_commit

我发现文档有点难读,但innodb_flush_log_at_trx_commit可以取 1,2,0 的值:

  • 为 1 时,每次提交时将日志缓冲区刷新到日志文件,每次提交时将日志文件刷新到磁盘。
  • 对于 2,每次提交都会将日志缓冲区刷新到日志文件,并且大约每 1-2 秒将日志文件刷新到磁盘。
  • 为 0 时,日志缓冲区每秒刷新到日志文件,日志文件每秒刷新到磁盘。

实际上,按照报告和记录的顺序 (1,2,0),您应该获得更高的交易业绩以增加风险。

话虽如此,我发现innodb_flush_log_at_trx_commit=0innodb_flush_log_at_trx_commit=2. 此外,当我将它切换到 2 时,坏实例的情况立即得到改善(请注意,您可以随时更改它)。

所以,我的问题是,你的设置是什么?请注意,我不是在责怪这个参数,而是强调它的上下文与这个问题有关。

于 2010-11-09T22:38:25.900 回答
1

我在使用 INNODB 表时遇到了这个问题。(而且 INNODB 索引的重写速度甚至比 MISAM 还要慢)

我想您正在对其他一些表执行多个其他查询,所以问题是 MySQL 必须处理文件中的磁盘写入,这些文件变得更大并且需要为这些文件分配额外的空间。

如果您使用 MISAM 表,我强烈建议您使用

LOAD DATA INFILE 'file-on-disk' INTO TABLE `tablename` 

命令; MYISAM 的速度非常快(即使使用主键),文件可以格式化为 csv,您可以指定列名(或者您可以将 NULL 作为自动增量字段的值)。

在此处查看 MYSQL 文档

于 2010-09-16T08:35:07.683 回答
1

我要给你的第一个提示是禁用自动提交功能而不是手动提交。

LOCK TABLES a WRITE;
... DO INSERTS HERE
UNLOCK TABLES;

这有利于性能,因为索引缓冲区仅在所有 INSERT 语句完成后刷新到磁盘一次。通常,索引缓冲区刷新的次数与 INSERT 语句的次数一样多。

但最好是你能做的最好的事情,如果在你的应用程序中这是可能的,你可以用一个单一的选择来做一个批量插入。

这是通过矢量绑定完成的,这是您可以采用的最快方式。

Instead
of:
"INSERT INTO tableName values()"
DO
"INSERT INTO tableName values(),(),(),().......(n) " ,

但仅当您使用的 mysql 驱动程序可以进行参数向量绑定时才考虑此选项。

否则,我会倾向于第一种可能性,并为每 1000 次插入锁定表。不要将其锁定为 100k 插入,因为您会遇到缓冲区溢出。

于 2010-09-16T08:46:32.953 回答
1

您可以再创建一个包含 400 个(非空)列的表并再次运行您的测试吗?如果慢插入的数量变得更高,这可能表明 MySQL 正在浪费时间写入您的记录。(我不知道它是如何工作的,但他可能正在分配更多的块,或者移动一些东西以避免碎片......真的不知道)

于 2010-09-22T14:37:05.750 回答
1

我们升级到 MySQL 5.1,在此事件中,查询缓存成为很多“释放项目?”的问题。线程状态。然后我们删除了查询缓存。

升级到 MySQL 5.1 或删除查询缓存解决了这个问题。

仅供参考,给未来的读者。

-丹尼尔

于 2010-12-09T23:02:31.390 回答
1

我们遇到了完全相同的问题并在这里报告: http ://bugs.mysql.com/bug.php?id=62381

我们正在使用 5.1.52,还没有解决方案。我们可能需要关闭 QC 以避免这种性能影响。

于 2011-09-22T10:28:38.577 回答
1

如果您使用 for 循环一次使用多个插入,那么请在每个循环后使用 PHP 的 sleep("time in seconds") 函数休息一下。

于 2016-07-22T05:39:04.807 回答
0

在 Myisam 性能上阅读此内容:http: //adminlinux.blogspot.com/2010/05/mysql-allocating-memory-for-caches.html

搜索:

'MyISAM 密钥块大小密钥块大小很重要'(减去单引号),这可能是正在发生的事情。我认为他们用 5.1 修复了其中一些类型的问题

于 2010-09-21T19:49:12.817 回答
0

你能检查磁盘子系统的统计数据吗?I/O 是否饱和?这听起来像是内部数据库工作正在将内容刷新到磁盘/日志。

于 2010-09-24T15:10:43.230 回答
0

要检查您的磁盘是否表现不佳,如果您在 Windows 中,您可以创建一个批处理 cmd 文件来创建 10,000 个文件:

@echo OFF
FOR /L %%G IN (1, 1, 10000) DO TIME /T > out%%G.txt

将其保存在临时目录中,例如 test.cmd

使用 /E:ON 参数启用运行 CMD 的命令扩展

CMD.exe /E:ON

然后运行你的批处理,看看第一个和最后一个输出文件之间的时间是否以秒或分钟为单位不同。

在 Unix/Linux 上,您可以编写类似的 shell 脚本。

于 2010-09-27T15:55:54.230 回答
0

服务器中是否有SSD驱动器?一些 SSD 驱动器会出现“studder”,这可能会导致您的症状。

无论如何,我会尝试找出延迟是否发生在 MySQL 或磁盘子系统中。

您的服务器是什么操作系统,MySQL 数据在什么文件系统上?

于 2010-10-02T05:29:42.700 回答