[英]Improve MySQL query speed with lots of joins
I have a query in MySQL which uses multiple joins and it runs slow at the moment - on average it is taking around 35 seconds to run. 我在MySQL中有一个查询,该查询使用多个联接,目前运行缓慢-平均而言,运行大约需要35秒。
The query is: 查询是:
SELECT t.id,
CASE t.emp_accepted
WHEN '1' THEN 'No'
WHEN '0' THEN 'Yes'
END AS accepted,
e.department,
e.works_id,
e.first_name,
e.sur_name,
e.job_title,
e.job_status,
e.site_id,
e.manager,
d1.department_name AS dept_name,
d2.department_name AS sub_dept_name,
temp_hours_worked.hours AS hours,
s.office_name AS site_name,
CONCAT(e2.first_name, ' ', e2.sur_name) AS manager_name,
CONCAT(e3.first_name, ' ', e3.sur_name) AS validated_by
FROM time t
LEFT JOIN employee e
ON t.employee_id = e.employee_id
LEFT JOIN departments d1
ON e.department = d1.id
LEFT JOIN departments d2
ON e.sub_department = d2.id
LEFT JOIN site s
ON e.site_id = s.id
LEFT JOIN employee e2
ON e.manager = e2.id
LEFT JOIN employee e3
ON t.manager_id = e3.id
LEFT JOIN temp_hours_worked
ON temp_hours_worked.week_beginning = t.week_beginning
AND temp_hours_worked.employee_id = t.employee_id
AND temp_hours_worked.company_id=?
WHERE t.company_id = ?;
Explain: 说明:
+----+-------------+-------------------+--------+---------------+-------------+---------+-----------------------------------------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------------+--------+---------------+-------------+---------+-----------------------------------------+------+-------+
| 1 | SIMPLE | t | ref | company_id | company_id | 4 | const | 5566 | |
| 1 | SIMPLE | e | ref | employee_id | employee_id | 4 | DBNAME.t.employee_id | 1 | |
| 1 | SIMPLE | d1 | eq_ref | PRIMARY | PRIMARY | 4 | DBNAME.e.department | 1 | |
| 1 | SIMPLE | d2 | eq_ref | PRIMARY | PRIMARY | 4 | DBNAME.e.sub_department | 1 | |
| 1 | SIMPLE | s | eq_ref | PRIMARY | PRIMARY | 4 | DBNAME.e.site_id | 1 | |
| 1 | SIMPLE | e2 | eq_ref | PRIMARY | PRIMARY | 4 | DBNAME.e.manager | 1 | |
| 1 | SIMPLE | e3 | eq_ref | PRIMARY | PRIMARY | 4 | DBNAME.t.manager_id | 1 | |
| 1 | SIMPLE | temp_hours_worked | ref | company_id | company_id | 4 | const | 5566 | |
+----+-------------+-------------------+--------+---------------+-------------+---------+-----------------------------------------+------+-------+
MySQL version is 5.5.31 running on Centos 6.5 64 bit and the server is 8 core, 4GB RAM with SSD disks. MySQL版本是5.5.31,运行于64位的Centos 6.5上,服务器是8核,4GB RAM和SSD磁盘。 Load average on the box is: 盒子上的平均负载为:
load average: 0.24, 0.29, 0.29
and free memory shows as: 可用内存显示为:
total used free shared buffers cached
Mem: 3880 3067 813 0 177 1065
-/+ buffers/cache: 1825 2055
Swap: 1023 0 1023
Disk space is OK: 磁盘空间还可以:
Filesystem Size Used Avail Use% Mounted on
/dev/xvda1 45G 11G 32G 26% /
tmpfs 1.9G 0 1.9G 0% /dev/shm
/usr/tmpDSK 1008M 51M 907M 6% /tmp
Output from hdparm -Tt /dev/xvda1 hdparm -Tt / dev / xvda1的输出
Timing cached reads: 12538 MB in 1.99 seconds = 6297.76 MB/sec
Timing buffered disk reads: 826 MB in 3.00 seconds = 275.27 MB/sec
my.cnf: my.cnf文件:
[mysql]
# CLIENT #
port = 3306
socket = /var/lib/mysql/mysql.sock
[mysqld]
local-infile=0
# GENERAL #
user = mysql
default_storage_engine = InnoDB
socket = /var/lib/mysql/mysql.sock
pid_file = /var/lib/mysql/mysql.pid
# MyISAM #
key_buffer_size = 32M
myisam_recover = FORCE,BACKUP
# SAFETY #
max_allowed_packet = 16M
max_connect_errors = 1000000
skip_name_resolve
#sql_mode = NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY
sysdate_is_now = 1
innodb = FORCE
#innodb_strict_mode = 1
# DATA STORAGE #
datadir = /var/lib/mysql/
# BINARY LOGGING #
log_bin = /var/lib/mysql/mysql-bin
expire_logs_days = 14
sync_binlog = 1
# CACHES AND LIMITS #
tmp_table_size = 32M
max_heap_table_size = 32M
query_cache_type = 0
query_cache_size = 0
max_connections = 500
thread_cache_size = 50
open_files_limit = 65535
table_definition_cache = 4096
table_open_cache = 4096
# INNODB #
innodb_flush_method = O_DIRECT
innodb_log_files_in_group = 2
innodb_log_file_size = 128M
innodb_flush_log_at_trx_commit = 1
innodb_file_per_table = 1
innodb_buffer_pool_size = 1456M
# LOGGING #
log_error = /var/lib/mysql/mysql-error.log
#log_queries_not_using_indexes = 1
slow_query_log = 1
slow_query_log_file = /var/lib/mysql/mysql-slow.log
The columns being queried/joined are all necessary and cannot be removed and I realise there is no index on quite a few of the columns but as they are only single rows I am not sure it matters - is there anything else I can do to speed this query up? 正在查询/联接的列都是必需的,无法删除,我意识到相当多的列上没有索引,但是由于它们只是单行,因此我不确定这很重要-还有什么我可以做的事情来加快速度这个查询了吗?
This query should never, ever be that slow on those hardware specs. 在这些硬件规格上,此查询永远不会那么慢。 The explain
output indicates that all joined fields use pretty optimal indexes, and only scans a mere 5566 rows. explain
输出表明所有联接的字段都使用最佳索引,仅扫描5566行。 The only index improvement could be a combined index on temp_hours_worked
on fields week_beginning, employee_id, company_id
but that's never going to be be much of a difference. 唯一的索引改进可以是在week_beginning, employee_id, company_id
字段上的temp_hours_worked
上的组合索引week_beginning, employee_id, company_id
但这不会有太大的区别。 There aren't even any filesorts or temp tables according to the explain output. 根据说明输出,甚至没有任何文件排序或临时表。
I suspect you're either running into locking issues (the load you show is low, but doesn't tell how many simultaneous queries are running on these same tables) or your MySQL is incredibly underpowered by config (using the default tiny.config
settings or comparable). 我怀疑您是在遇到锁定问题(显示的负载很低,但是没有告诉您在这些相同的表上正在运行多少同时查询),或者您的MySQL的配置(使用默认的tiny.config
设置)的功能不足或类似)。
Things to check: 检查事项:
hdparm -Tt /dev/sdX
to test drive performance - the SSD disks or RAID array may be borked 使用hdparm -Tt /dev/sdX
测试驱动器性能-SSD磁盘或RAID阵列可能损坏 buffer
settings in my.cnf
at least at twice their current value, you have RAM to spare. 不要犹豫,将所有buffer
设置至少放置在my.cnf
,至少为其当前值的两倍,这样就可以腾出RAM。 A few may warrant extremely higher settings. 一些可能需要更高的设置。 A script like MySQLTuner may be of help with this. 像MySQLTuner这样的脚本可能对此有所帮助。 Also check whether the issue is reproducable on another server. 还要检查问题是否在另一台服务器上可重现。
A good beginning to up MySQL buffer values is adding this bit to your my.cnf
: MySQL缓冲区值的一个很好的开始是将此位添加到my.cnf
:
key_buffer = 768M
table_cache = 1024
sort_buffer_size = 4M
read_buffer_size = 4M
read_rnd_buffer_size = 16M
myisam_sort_buffer_size = 128M
query_cache_size = 128M
thread_concurrency = 16
table_open_cache = 2048
tmp_table_size = 64M
max_heap_table_size = 64M
You can review current values in phpMyAdmin (server -> variables). 您可以在phpMyAdmin中查看当前值(服务器->变量)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.