2015-09-02 31 views
1

我的MySQL查詢有大量數據訪問時出現問題,當查詢使用連接進行優化時,它會在122秒內爲一週數據提供輸出。然後對於一個月的數據,該過程需要526秒。 我想優化這個查詢每年更少的處理時間或者是否有任何方法來優化MySQL設置?用於JOIN大型表的MySQL查詢優化

表細節。 我指的是兩個表,其中包括mdiaries和tv_diaries,在這兩個表中我都有索引相關列,在mdiaries表中tv_diaries中有2661331行和27074645行。

mdiaries表:

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。

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秒才能執行。

$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文件。

[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 
+0

只需使用左連接代替內部連接,因爲您會看到性能 –

+0

內部連接通常比左側連接快,所以通過這種方式它已經正確寫入。我想知道如果你真的需要採取所有的結果,如果一個極限會有所幫助 – Aleeeeee

+0

@SatenderK我已經測試了左加入,但它比內加入更好,比左加入 –

回答

2

這是您的查詢:

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)

該查詢有問題,但這些可能有所幫助。

+0

謝謝!一個月的數據首先需要600秒,但添加多個索引時,它會減少到160秒。我需要知道的是,我添加了JOIN查詢,但是當我沒有JOIN查詢時,它比預期花費的時間要少,原因是什麼? –

+0

@MalithWijethunga。 。 。加入需要額外的工作。 –

0

嘗試在GROUP BY子句中引用的所有列上添加多列索引,如提到的in the documentation

INDEX grp (date, timeslot_id, tv_channel_id, district, area) 
+0

這也爲查詢處理提供了效率。謝謝! –

0

不知道,但它可以爲您提供更好的性能 -

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; 

你也可以檢查你的數據庫配置設置,因爲我看到下面issues-

  1. innodb_file_per_table = 1評論說:如果它是真的,那麼數據將被存儲在單個ibd文件中而不是表格中。

  2. tmp_table_size和max_heap_table_size可以提高性能,因爲您試圖從繁重的表中獲取數據。因此如果您的查詢正在磁盤上創建臨時表,請嘗試將它們都設置爲至少100M,以避免在磁盤上創建臨時表。

  3. 因爲您正在使用group by,因此sort_buffer_size變量可以幫助您增加它。可以設置2M。

  4. join_buffer_size太高,應該在2M附近才能設置最大值。 8M但不是512M,因爲它會話明智,所以吃掉你所有的記憶。

  5. 您還設置了query_cache_size與512M一樣太高,所以從這裏釋放內存,您也可以通過mysqltuner報告檢查實際上您是否獲得了緩存查詢的好處,如果不是,那麼您可以禁用它。

+0

QC不應該設置得很高 - 它會使修剪成本更高。 –

+0

我的意思是說他已經把它設得太高了,對不起,因爲這裏的含義看起來不同。現在我已經糾正了。感謝瑞克吸引我注意它。 –

+0

@RickJames:我從你身上學到了很多東西,與其他人在這裏分享...... :) –

0

也許你可以使用一個物化視圖保存查詢的結果,並定期刷新它(月〜15天呢?)

這不會優化您的查詢,但你的諮詢誰將會方式更快(它不會再計算)