首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >连接大型表的MySQL查询优化

连接大型表的MySQL查询优化
EN

Stack Overflow用户
提问于 2015-09-02 11:34:47
回答 4查看 2.6K关注 0票数 3

对于大数据访问,我的MySQL查询有问题,当使用join优化查询时,它在122秒内为一周的数据提供输出。然后,在一个月的数据,它需要526秒的进程。我希望优化这个查询,以减少每年的处理时间,或者如果有任何方法来优化MySQL设置的话?

表的细节。我指的是两个表( mdiaries和tv_diaries ),在这两个表中,我对相关列进行了索引,在mdiaries表中,tv_diaries中有2661331行和27074645行。

每日日记表:

代码语言:javascript
复制
  INDEX area (area),
  INDEX date (date),
  INDEX district (district),
  INDEX gaDivision (gaDivision),
  INDEX member_id (member_id),
  INDEX tv_channel_id (tv_channel_id),

tv_diaries。

代码语言:javascript
复制
  INDEX area (area),
  INDEX date (date),
  INDEX district (district),
  INDEX member_id (member_id),
  INDEX timeslot_id (timeslot_id),
  INDEX tv_channel_id (tv_channel_id),

这是我的查询,执行时间为122秒。

代码语言:javascript
复制
$sql = "SELECT COUNT(TvDiary.id) AS m_count,TvDiary.date,TvDiary.timeslot_id,TvDiary.tv_channel_id,TvDiary.district,TvDiary.area
FROM `mdiaries` AS Mdiary INNER JOIN `tv_diaries` AS TvDiary ON Mdiary.member_id = TvDiary.member_id
WHERE Mdiary.date >= '2014-01-01' AND Mdiary.date <= '2014-01-07'
AND TvDiary.date >= '2014-01-01' AND TvDiary.date <= '2014-01-07'
GROUP BY TvDiary.date,
TvDiary.timeslot_id,
TvDiary.tv_channel_id,
TvDiary.district,
TvDiary.area";

这是my.cnf文件。

代码语言:javascript
复制
    [mysqld]

## General
datadir                         = /var/lib/mysql
tmpdir                          = /var/lib/mysqltmp
socket                          = /var/lib/mysql/mysql.sock
skip-name-resolve
sql-mode                        = NO_ENGINE_SUBSTITUTION
#event-scheduler                = 1

## Networking
back-log                        = 100
#max-connections                = 200
max-connect-errors              = 10000
max-allowed-packet              = 32M
interactive-timeout             = 3600
wait-timeout                    = 600

### Storage Engines
#default-storage-engine         = InnoDB
innodb                          = FORCE

## MyISAM
key-buffer-size                 = 64M
myisam-sort-buffer-size         = 128M

## InnoDB
innodb-buffer-pool-size        = 16G
innodb_buffer_pool_instances    = 16
#innodb-log-file-size           = 100M
#innodb-log-buffer-size         = 8M
#innodb-file-per-table          = 1
#innodb-open-files              = 300

## Replication
server-id                       = 1
#log-bin                        = /var/log/mysql/bin-log
#relay-log                      = /var/log/mysql/relay-log
relay-log-space-limit           = 16G
expire-logs-days                = 7
#read-only                      = 1
#sync-binlog                    = 1
#log-slave-updates              = 1
#binlog-format                  = STATEMENT
#auto-increment-offset          = 1
#auto-increment-increment       = 2

## Logging
log-output                      = FILE
slow-query-log                  = 1
slow-query-log-file             = /var/log/mysql/slow-log
#log-slow-slave-statements
long-query-time                 = 2

##
query_cache_size        = 512M
query_cache_type        = 1
query_cache_limit       = 2M
join_buffer_size        = 512M
thread_cache_size       = 128

[mysqld_safe]
log-error                       = /var/log/mysqld.log
open-files-limit                = 65535

[mysql]
no-auto-rehash
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-09-02 11:39:32

这是您的查询:

代码语言:javascript
复制
SELECT COUNT(t.id) AS m_count, t.date, t.timeslot_id, t.tv_channel_id,
       t.district, t.area
FROM `mdiaries` m INNER JOIN
     `tv_diaries` t
     ON m.member_id = t.member_id
WHERE m.date >= '2014-01-01' AND m.date <= '2014-01-07' AND
      t.date >= '2014-01-01' AND t.date <= '2014-01-07'
GROUP BY t.date, t.timeslot_id, t.tv_channel_id, t.district, t.area;

我将从复合索引开始:tv_diaries(date, member_id)mdiaries(member_id, date)

这个查询是有问题的,但这些可能会有所帮助。

票数 2
EN

Stack Overflow用户

发布于 2015-09-02 11:45:10

尝试在GROUP BY子句中引用的所有列上添加多列索引,如提到的在文件中

代码语言:javascript
复制
INDEX grp (date, timeslot_id, tv_channel_id, district, area)
票数 2
EN

Stack Overflow用户

发布于 2015-09-02 12:45:02

不确定,但它能给你更好的表现-

代码语言:javascript
复制
SELECT COUNT(t.id) AS m_count, t.date, t.timeslot_id, t.tv_channel_id, t.district, t.area
FROM `mdiaries` m 
JOIN 
(
SELECT t.id, t.date, t.timeslot_id, t.tv_channel_id, t.district, t.area, t.member_id 
FROM `tv_diaries` AS t
WHERE t.date >= '2014-01-01' AND t.date <= '2014-01-07' 
) t ON m.member_id = t.member_id
WHERE m.date >= '2014-01-01' AND m.date <= '2014-01-07' 
GROUP BY t.date, t.timeslot_id, t.tv_channel_id, t.district, t.area;

您也可以检查您的db配置设置,正如我在下面看到的问题-

  1. innodb_file_per_table=1被注释了:如果它是真的,那么数据将存储在单个ibd文件中,而不是表wise中。
  2. tmp_table_size和max_heap_table_size可以提高性能,因为您试图从繁重的表中获取数据。因此,如果您的查询正在磁盘上创建临时表,请尝试将它们设置为至少100米,以避免在磁盘上创建临时表。
  3. 由于您正在使用组by,所以如果您增加sort_buffer_size变量,它可以帮助您。可以设定200万。
  4. join_buffer_size太高了,应该在2米左右左右可以设定最大值。8米,但不是512米,因为它使用的会议明智,所以吃了你的所有记忆。
  5. 此外,您还将query_cache_size设置为512米,因此从这里释放内存,您还可以通过mysqltuner报告检查您是否正在从缓存查询中获益,如果没有,则可以禁用它。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32352058

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档