简体   繁体   English

通过大量联接提高MySQL查询速度

[英]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: 检查事项:

  • Use hdparm -Tt /dev/sdX to test drive performance - the SSD disks or RAID array may be borked 使用hdparm -Tt /dev/sdX测试驱动器性能-SSD磁盘或RAID阵列可能损坏
  • Check your performance settings. 检查您的性能设置。 Don't hesitate to put all 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM