5

我们有一个 XMPP 应用程序,它使用 MySQL 来存储信息。到目前为止,我们没有遇到任何特定的负载问题,但我正在努力为最坏的情况(或最好的,就用户而言;))做好准备。

安装此 MySQL 服务器的主机是具有 2GB RAM 的 Slicehost 切片。

昨天,我激活了慢查询日志记录,以确保我们实际上没有什么慢的。不幸的是,似乎实际上发现了很多慢查询:

从 /var/log/mysql/mysql-slow.log 读取 mysql 慢查询日志
计数:109 Time=25.57s (2787s) Lock=0.00s (0s) Rows=1.0 (109), xxxxx[xxxxx]@[172.21.xxx.xxx]
  SELECT * FROM `feeds` WHERE (`id` = 'S') LIMIT N

这对我来说真的很奇怪,因为 id 实际上是一个主键......表是 InnoDB

我做了一个解释:

mysql> EXPLAIN SELECT * FROM `feeds` WHERE (`id` = '2650') LIMIT 1;

 +----+-------------+--------+-------+-------------- -+---------+---------+--------+------+--------+
 | 编号 | 选择类型 | 表| 类型 | 可能的键 | 关键 | key_len | 参考 | 行 | 额外 |
 +----+-------------+--------+-------+-------------- -+---------+---------+--------+------+--------+
 | 1 | 简单 | 饲料 | 常量 | 初级 | 初级 | 4 | 常量 | 1 | |
 +----+-------------+--------+-------+-------------- -+---------+---------+--------+------+--------+
 一组中的 1 行(0.00 秒)

发生这种情况一定有另一个原因。在我们的日志中实际上有很多类似的慢查询(使用主键的查询)。

我认为在这里发布 MySQL 设置是有意义的:

mysql> 显示变量;
+---------------------------------+---------------- --------------+
| 变量名 | 价值 |
+---------------------------------+---------------- --------------+
| auto_increment_increment | 1 |
| auto_increment_offset | 1 |
| automatic_sp_privileges | 开 |
| 后台日志 | 50 |
| 基于| /usr/ |
| binlog_cache_size | 32768 |
| bulk_insert_buffer_size | 8388608 |
| character_set_client | 拉丁语1 |
| 字符集连接 | 拉丁语1 |
| 字符集数据库 | 拉丁语1 |
| 字符集文件系统 | 二进制 |
| 字符集结果 | 拉丁语1 |
| character_set_server | 拉丁语1 |
| 字符集系统 | utf8 |
| 字符集目录 | /usr/share/mysql/charsets/ |
| collat​​ion_connection | latin1_swedish_ci |
| collat​​ion_database | latin1_swedish_ci |
| 排序服务器 | latin1_swedish_ci |
| 完成类型 | 0 |
| 并发插入 | 1 |
| 连接超时 | 10 |
| 数据目录 | /var/lib/mysql/ |
| 日期格式 | %Y-%m-%d |
| 日期时间格式 | %Y-%m-%d %H:%i:%s |
| default_week_format | 0 |
| delay_key_write | 开 |
| 延迟插入限制 | 100 |
| 延迟插入超时 | 300 |
| 延迟队列大小 | 1000 |
| div_precision_increment | 4 |
| keep_files_on_create | 关闭 |
| engine_condition_pushdown | 关闭 |
| expire_logs_days | 10 |
| 冲洗 | 关闭 |
| 冲洗时间 | 0 |
| ft_boolean_syntax | + -><()~*:""&| |
| ft_max_word_len | 84 |
| ft_min_word_len | 4 |
| ft_query_expansion_limit | 20 |
| ft_stopword_file | (内置)|
| group_concat_max_len | 1024 |
| 有存档| 是 |
| 有_bdb | 否 |
| have_blackhole_engine | 是 |
| 有压缩 | 是 |
| 加密货币 | 是 |
| 有_csv | 是 |
| have_dynamic_loading | 是 |
| have_example_engine | 否 |
| have_federated_engine | 已禁用 |
| 有几何 | 是 |
| 有_innodb | 是 |
| 有_isam | 否 |
| have_merge_engine | 是 |
| 有_ndbcluster | 已禁用 |
| 有_openssl | 已禁用 |
| 有_ssl | 已禁用 |
| 有查询缓存 | 是 |
| 有_raid | 否 |
| 有_rtree_keys | 是 |
| 有符号链接 | 是 |
| 主机名 | Superfeedr 数据库 |
| 初始化连接 | |
| 初始化文件 | |
| 初始化奴隶 | |
| innodb_additional_mem_pool_size | 1048576 |
| innodb_autoextend_increment | 8 |
| innodb_buffer_pool_awe_mem_mb | 0 |
| innodb_buffer_pool_size | 1073741824 |
| innodb_checksums | 开 |
| innodb_commit_concurrency | 0 |
| innodb_concurrency_tickets | 500 |
| innodb_data_file_path | ibdata1:10M:自动扩展 |
| innodb_data_home_dir | |
| innodb_adaptive_hash_index | 开 |
| innodb_doublewrite | 开 |
| innodb_fast_shutdown | 1 |
| innodb_file_io_threads | 4 |
| innodb_file_per_table | 开 |
| innodb_flush_log_at_trx_commit | 2 |
| innodb_flush_method | O_DIRECT |
| innodb_force_recovery | 0 |
| innodb_lock_wait_timeout | 50 |
| innodb_locks_unsafe_for_binlog | 关闭 |
| innodb_log_arch_dir | |
| innodb_log_archive | 关闭 |
| innodb_log_buffer_size | 4194304 |
| innodb_log_file_size | 5242880 |
| innodb_log_files_in_group | 2 |
| innodb_log_group_home_dir | ./ |
| innodb_max_dirty_pages_pct | 90 |
| innodb_max_purge_lag | 0 |
| innodb_mirrored_log_groups | 1 |
| innodb_open_files | 300 |
| innodb_rollback_on_timeout | 关闭 |
| innodb_support_xa | 开 |
| innodb_sync_spin_loops | 20 |
| innodb_table_locks | 开 |
| innodb_thread_concurrency | 8 |
| innodb_thread_sleep_delay | 10000 |
| 交互超时 | 28800 |
| join_buffer_size | 131072 |
| key_buffer_size | 16777216 |
| key_cache_age_threshold | 300 |
| key_cache_block_size | 1024 |
| key_cache_division_limit | 100 |
| 语言 | /usr/share/mysql/英文/ |
| 大文件支持| 开 |
| 大页面大小 | 0 |
| 大页 | 关闭 |
| lc_time_names | zh_CN |
| 许可证 | 通用公共许可证 |
| 本地文件 | 开 |
| 锁定内存 | 关闭 |
| 日志 | 关闭 |
| 日志_bin | 关闭 |
| log_bin_trust_function_creators | 关闭 |
| 日志错误 | |
| log_queries_not_using_indexes | 开 |
| log_slave_updates | 关闭 |
| log_slow_queries | 开 |
| 日志警告 | 1 |
| long_query_time | 3 |
| 低优先级更新 | 关闭 |
| 小写文件系统 | 关闭 |
| 小写表名 | 0 |
| max_allowed_pa​​cket | 16777216 |
| max_binlog_cache_size | 18446744073709547520 |
| max_binlog_size | 104857600 |
| 最大连接错误 | 10 |
| 最大连接数 | 2000 |
| max_delayed_threads | 20 |
| 最大错误计数 | 64 |
| max_heap_table_size | 16777216 |
| max_insert_delayed_threads | 20 |
| max_join_size | 18446744073709551615 |
| max_length_for_sort_data | 1024 |
| max_prepared_stmt_count | 16382 |
| max_relay_log_size | 0 |
| max_seeks_for_key | 18446744073709551615 |
| 最大排序长度 | 1024 |
| max_sp_recursion_depth | 0 |
| max_tmp_tables | 32 |
| max_user_connections | 0 |
| max_write_lock_count | 18446744073709551615 |
| 多范围计数 | 256 |
| myisam_data_pointer_size | 6 |
| myisam_max_sort_file_size | 9223372036853727232 |
| myisam_recover_options | 备份 |
| myisam_repair_threads | 1 |
| myisam_sort_buffer_size | 8388608 |
| myisam_stats_method | nulls_unequal |
| ndb_autoincrement_prefetch_sz | 1 |
| ndb_force_send | 开 |
| ndb_use_exact_count | 开 |
| ndb_use_transactions | 开 |
| ndb_cache_check_time | 0 |
| ndb_connectstring | |
| net_buffer_length | 16384 |
| net_read_timeout | 30 |
| net_retry_count | 10 |
| net_write_timeout | 60 |
| 新 | 关闭 |
| 旧密码 | 关闭 |
| open_files_limit | 10000 |
| optimizer_prune_level | 1 |
| 优化器搜索深度 | 62 |
| pid_file | /var/run/mysqld/mysqld.pid |
| 插件目录 | |
| 港口| 3306 |
| preload_buffer_size | 32768 |
| 分析 | 关闭 |
| profiling_history_size | 15 |
| 协议版本 | 10 |
| 查询分配块大小 | 8192 |
| 查询缓存限制 | 1048576 |
| query_cache_min_res_unit | 4096 |
| 查询缓存大小 | 16777216 |
| 查询缓存类型 | 开 |
| query_cache_wlock_invalidate | 关闭 |
| query_prealloc_size | 8192 |
| range_alloc_block_size | 4096 |
| 读取缓冲区大小 | 131072 |
| 只读 | 关闭 |
| read_rnd_buffer_size | 262144 |
| 中继日志 | |
| 中继日志索引 | |
| 中继日志信息文件 | 中继日志信息 |
| 中继日志清除 | 开 |
| 中继日志空间限制 | 0 |
| rpl_recovery_rank | 0 |
| 安全身份验证 | 关闭 |
| 安全文件隐私 | |
| server_id | 0 |
| 跳过外部锁定 | 开 |
| 跳过网络 | 关闭 |
| skip_show_database | 关闭 |
| slave_compressed_protocol | 关闭 |
| slave_load_tmpdir | /tmp/ |
| slave_net_timeout | 3600 |
| slave_skip_errors | 关闭 |
| slave_transaction_retries | 10 |
| 慢启动时间 | 2 |
| 插座 | /var/run/mysqld/mysqld.sock |
| 排序缓冲区大小 | 2097144 |
| sql_big_selects | 开 |
| sql_mode | |
| sql_notes | 开 |
| sql_warnings | 关闭 |
| ssl_ca | |
| ssl_capath | |
| ssl_cert | |
| ssl_cipher | |
| ssl_key | |
| 存储引擎 | MyISAM |
| 同步二进制日志 | 0 |
| 同步框架 | 开 |
| system_time_zone | 世界标准时间 |
| 表缓存 | 64 |
| table_lock_wait_timeout | 50 |
| 表类型 | MyISAM |
| 线程缓存大小 | 8 |
| 线程堆栈 | 131072 |
| 时间格式 | %H:%i:%s |
| 时区 | 系统 |
| 定时互斥体 | 关闭 |
| tmp_table_size | 33554432 |
| tmpdir | /tmp |
| transaction_alloc_block_size | 8192 |
| transaction_prealloc_size | 4096 |
| tx_isolation | 已阅读 |
| update_views_with_limit | 是 |
| 版本 | 5.0.67-0ubuntu6-日志 |
| 版本评论 | (Ubuntu) |
| version_compile_machine | x86_64 |
| version_compile_os | debian-linux-gnu |
| 等待超时 | 28800 |
+---------------------------------+---------------- --------------+
237 行(0.00 秒)

我们的大多数请求都是“基本的”,但是,我们需要极快的速度!

关于实际上可能使 MySQL 如此缓慢的任何想法?

[摘要]总结各种答案:

  • 去掉“LIMIT”,把WHERE id = “X”改成WHERE id = X
  • 确保我没有任何不时运行的脚本(备份或其他)会消耗大量资源
  • 确保“主机”实际上不是罪魁祸首。
4

8 回答 8

3

查看慢速的均值和方差,您的 VM 主机存在问题(不幸的是,它不在您的控制范围内)。

对于那些指出内存/磁盘 I/O 的人来说,这些数字太大了。磁盘应该在 100 毫秒内返回,而不是几秒钟。

于 2009-06-10T16:50:32.560 回答
1

如果 id 是主键,为什么要添加 LIMIT 子句?

您是否尝试过指定所需的列名而不是使用 *?

另外,您的 Id 列是 int 吗?通过指定 '1' 而不是 1,您可能没有使用索引。

尝试

SELECT * FROM Feeds WHERE id = 1

而不是

SELECT * FROM Feeds WHERE id = '1'

编辑评论

在我看来,最好明确指定列名,因为将来您可能需要向该表中添加应用程序不需要的列。那时,您开始提取比需要更多的数据。

于 2009-06-10T16:32:08.133 回答
1

您的查询非常简单,并且鉴于 id 是主键,在正常情况下,即使在巨大的表上也不会花费那么长时间。这里只是一个猜测,但也许服务器是问题所在?据我了解(从查看他们主页的 30 秒开始),Slicehost 为您提供了更强大服务器的虚拟机“切片”。会不会是同一台服务器上的其他片不时地进行大量磁盘读取,暂时窃取您的所有资源?或者,当管理员从机器上为其他用户创建/删除切片时,可能会发生这种情况。

这种情况经常发生吗?

于 2009-06-10T16:45:09.900 回答
1

不幸的是,去年我在这种事情上获得了很多经验。

我同意其他人的观点,这可能是 CPU/磁盘延迟问题(由于虚拟主机)。有什么方法可以从主机获取磁盘延迟数?也许有尖峰。

我也同意该查询在指定限制子句和引用索引时有点奇怪。SELECT * 位我完全可以理解。

我猜 InnoDB 没有足够的内存,但是行数太少并且给 InnoDB 1 gig,不是这样。

我猜这个查询是错误的。我以前见过 MySQL 做这种事情。某些查询耗时过长或导致其他查询开始堆积。但是您看到的查询时间过长是一些简单的小事情,不应该花费很长时间。

我有几个建议给你:

  • 是否有某种正在运行的自动备份可能会锁定表?
  • 这是否发生在任何定期或可预测的时间间隔内?
  • 发生这种情况时,您是否曾经登录并查看过完整的进程列表?
  • 它是否与任何特定的东西一致(任何时候人们运行某个报告等)?
  • 您是否有任何非常大的表在处理查询时可能会占用您的所有内存,从而阻止该表进入(不太可能)?
  • 一直都是这样吗?是最近开始的吗?MySQL版本有变化吗?您是否可以尝试另一个版本的 MySQL(更新点版本、Percona Performance 版本等)?

有时在此过程中查看完整的流程列表可能是最有帮助的。

去年我们遇到这种事情的时候,是看进程列表才最终抓住了真正的问题。

于 2009-06-10T17:03:49.117 回答
1

我以前见过这个问题。

您的索引在一个整数字段上,并且您的 where 子句键是一个string。您的索引被您导致类型转换的事实所击败。在 where 子句中取消引用您的密钥。

我对mysql的这种行为感到非常惊讶,令人失望的是它无法检测到何时发生这种情况。

于 2009-06-10T17:29:23.870 回答
0

如果表大于内存缓存中可以保存的表,那么可能是这些查询中的某些查询需要在某些不幸的时刻触及磁盘,而其他东西给它们带来了很大的负载?

MySQL 调优有时有点像魔法。高 key-buffer 缓存争用也会导致明显的减速。

您也可以尝试在mysql 性能博客中搜索线索和似是而非的理论。

于 2009-06-10T16:39:54.560 回答
0

这可能是由于名称解析延迟造成的,具体取决于您的设置。您可以使用以下方法测试从服务器查找 DNS 的速度:

nslookup www.domain.com

如果您的响应速度很慢,请尝试在/etc/my.cnf文件中设置以下内容:

skip-name-resolve
# and/or:
skip-networking

此外,最好绑定 IP 地址和端口号以消除对连接路径的怀疑:

bind-address=127.0.0.1
port=3306

否则,我会查看表锁定并从那里进行故障排除。

于 2017-06-21T20:47:53.113 回答
-1

如果您使用的是 MyISAM,您可能会遇到并发问题。

于 2009-06-10T16:39:48.947 回答