2017-02-09 275 views
1

我怎麼可以繼續對我的響應時間快多了,大約有響應的平均時間是0.2秒(8039記錄在我的項目表& 81記錄在我的跟蹤表)優化查詢

查詢

SELECT a.name, b.cnt FROM `items` a LEFT JOIN 
(SELECT guid, COUNT(*) cnt FROM tracking WHERE 
date > UNIX_TIMESTAMP(NOW() - INTERVAL 1 day) GROUP BY guid) b ON 
a.`id` = b.guid WHERE a.`type` = 'streaming' AND a.`state` = 1 
ORDER BY b.cnt DESC LIMIT 15 OFFSET 75 

跟蹤表結構

CREATE TABLE `tracking` (
`id` bigint(11) NOT NULL AUTO_INCREMENT, 
`guid` int(11) DEFAULT NULL, 
`ip` int(11) NOT NULL, 
`date` int(11) DEFAULT NULL, 
PRIMARY KEY (`id`), 
KEY `i1` (`ip`,`guid`) USING BTREE 
) ENGINE=InnoDB AUTO_INCREMENT=4303 DEFAULT CHARSET=latin1; 

項目表結構

CREATE TABLE `items` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`guid` int(11) DEFAULT NULL, 
`type` varchar(255) DEFAULT NULL, 
`name` varchar(255) DEFAULT NULL, 
`embed` varchar(255) DEFAULT NULL, 
`url` varchar(255) DEFAULT NULL, 
`description` text, 
`tags` varchar(255) DEFAULT NULL, 
`date` int(11) DEFAULT NULL, 
`vote_val_total` float DEFAULT '0', 
`vote_total` float(11,0) DEFAULT '0', 
`rate` float DEFAULT '0', 
`icon` text CHARACTER SET ascii, 
`state` int(11) DEFAULT '0', 
PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=9258 DEFAULT CHARSET=latin1; 
+1

您可以通過在表上添加實際的JOIN條件(WHERE a.column = b.column)開始。 –

+0

也使用'date'作爲字段可能會遇到麻煩。例如,我懷疑沒有滴答聲,因爲它寫道,那個查詢根本不起作用。 – LSerni

+0

請閱讀。 http://meta.stackoverflow.com/questions/271055/tips-for-asking-a-good-structured-query-language-sql-question/271056#271056然後,請[編輯]你的問題,以提供更多的細節。另外,專家提示,請不要在查詢中使用SELECT *,而在其中使用JOIN,當然不能在帶有GROUP BY的查詢中使用。 –

回答

2

您的查詢,如寫的,沒有太大的意義。它會在兩個表中生成所有可能的行組合,然後對它們進行分組。

你可能想這一點:來自於比較大的跟蹤表

SELECT a.*, b.cnt 
     FROM `items` a 
LEFT JOIN (
       SELECT guid, COUNT(*) cnt 
       FROM tracking 
       WHERE `date` > UNIX_TIMESTAMP(NOW() - INTERVAL 1 day) 
      GROUP BY guid 
      ) b ON a.guid = b.guid 
    ORDER BY b.cnt DESC 

這個查詢中的大容量數據。所以,你應該使用列(date, guid)添加一個複合索引。這將允許您的查詢通過date隨機訪問索引,然後掃描​​值。

ALTER TABLE tracking ADD INDEX guid_summary (`date`, guid); 

我想你會看到一個很好的性能改進。

專業提示:請勿使用SELECT *。相反,請在結果集中列出所需的列。例如,

SELECT a.guid, a.name, a.description, b.cnt 

爲什麼這很重要?

首先,它會讓你的軟件在將來有人向你的表格添加列時更具彈性。

其次,它告訴MySQL服務器只能繞過你想要的信息。這可以極大地提高性能,特別是當你的桌子變大時。

+0

不錯的答案 - 另一個重要的點 - 8000記錄不大。 – Hogan

+0

我已經在我的跟蹤表中創建了索引並刪除了*來指定我想要檢索的列,我的響應時間爲0,17 ms可能會減少? x) – LeSpotted44

+0

我有我的編輯我的答案和設置我的新查詢 – LeSpotted44

0

由於tracking的行數比items少很多,我會提出以下建議。

SELECT i.name, c.cnt 
    FROM 
    (
     SELECT guid, COUNT(*) cnt 
      FROM tracking 
      WHERE date > UNIX_TIMESTAMP(NOW() - INTERVAL 1 day) 
      GROUP BY guid 
    ) AS c 
    JOIN items AS i ON i.id = c.guid 
    WHERE i.type = 'streaming' 
     AND i.state = 1; 
    ORDER BY c.cnt DESC 
    LIMIT 15 OFFSET 75 

它將無法顯示其cnt爲0任何物品(你的版本會顯示與NULL的物品的數量。)

複合索引需要:

items: The PRIMARY KEY(id) is sufficient. 
tracking: INDEX(date, guid) -- "covering" 

其他問題:

  • 如果ip是一個IP地址,它需要是INT UNSIGNED。但是這僅涵蓋IPv4,而不涵蓋IPv6。
  • 看起來好像date不只是一個「日期」,而是一個日期+時間。請重命名以避免混淆。
  • float(11,0) - 請勿將FLOAT用於整數。請勿在FLOATDOUBLE上使用(m,n)INT UNSIGNED在這裏更有意義。

OFFSET在性能方面很調皮 - 它必須掃描跳過的記錄。但是,在您的查詢中,無法避免收集可能的行,對它們進行排序,超過75行,並且最終只交付15行。 (並且,不超過81,不會滿15)。

您使用的是什麼版本?對LEFT JOIN (SELECT ...)的優化進行了重要更改。請爲討論中的每個查詢提供EXPLAIN SELECT