我在我的應用程序中的簡單的SQL語句:SQL語句性能差,雖然使用索引
SELECT SQL_NO_CACHE key_event_id, MAX(report_ts) AS max_ts
FROM `key_event_reports`
WHERE report_model_id = 2
GROUP BY key_event_id;
的key_event_reports
表是中等大小(〜17M行),這是表的定義:
CREATE TABLE IF NOT EXISTS `key_event_reports` (
`key_event_report_id` int(20) NOT NULL AUTO_INCREMENT,
`report_model_id` int(5) NOT NULL,
`key_event_id` int(5) NOT NULL,
`title_id` int(15) NOT NULL,
`report_ts` datetime NOT NULL,
`report_time` time NOT NULL,
`total` int(7) NOT NULL DEFAULT '0',
`pos` int(7) NOT NULL DEFAULT '0',
`neg` int(7) NOT NULL DEFAULT '0',
`smooth_total` float NOT NULL DEFAULT '0',
`smooth_pos` float NOT NULL DEFAULT '0',
`smooth_neg` float NOT NULL DEFAULT '0',
`buzz` float NOT NULL DEFAULT '0',
`sentiment` float NOT NULL DEFAULT '0',
PRIMARY KEY (`key_event_report_id`),
UNIQUE KEY `key_event_id_4` (`key_event_id`,`report_model_id`,`title_id`,`report_ts`),
KEY `report_model_id` (`key_event_id`,`report_time`),
KEY `report_model_id_2` (`report_model_id`,`key_event_id`,`report_ts`),
KEY `key_event_id` (`key_event_id`,`report_model_id`,`report_time`,`title_id`,`smooth_total`),
KEY `key_event_id_3` (`key_event_id`,`report_model_id`,`report_time`,`title_id`,`smooth_pos`),
KEY `key_event_id_2` (`key_event_id`,`report_model_id`,`report_time`,`title_id`,`smooth_neg`),
KEY `get_latest_report` (`report_model_id`,`report_ts`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=16967636 ;
report_model_id始終爲2(數據庫中沒有其他模型,但可以很快更改),並且每10分鐘報告10個不同的key_events。
這個查詢需要很長時間沒有緩存(約20秒)。這個問題變得更糟,當上面的查詢被用作一個更大的語句子查詢:
SET @report_model_id = 2;
SET @message_id = ?;
SET @title_id = ?
SET @min_score = 5;
SET @min_message_id = (
SELECT MIN(message_id)
FROM `messages`
WHERE msg_time > DATE_SUB(NOW(), INTERVAL 20 MINUTE)
);
SELECT
ke.key_event_id AS key_event_id,
COALESCE(kermmid.message_id, MIN(mhke.message_id)) AS max_message_id,
ker_max.max_ts AS last_report_ts
FROM `key_events` ke
LEFT JOIN (
SELECT key_event_id, MAX(report_ts) AS max_ts
FROM `key_event_reports`
WHERE report_model_id = 2
GROUP BY key_event_id
) ker_max
ON (ker_max.key_event_id = ke.key_event_id)
LEFT JOIN `key_event_reports` ker
ON (
ker.key_event_id = ke.key_event_id
AND ker.report_model_id = @report_model_id
AND ker.title_id = @title_id
AND ker.report_ts = @actcurrent
)
LEFT JOIN `key_event_report_max_message_ids` kermmid
ON (
kermmid.key_event_id = ker.key_event_id
AND kermmid.report_model_id = ker.report_model_id
AND kermmid.report_ts = ker.report_ts
)
LEFT JOIN `messages_has_key_events` mhke
ON (
mhke.key_event_id = ke.key_event_id
AND mhke.title_id = @title_id
AND mhke.message_id > @min_message_id
AND mhke.message_id < @message_id
AND mhke.score > @min_score
)
GROUP BY
ke.key_event_id;
如果我使用子查詢在此,執行時間從大約50毫秒到> 20多歲的太無二。
這可能是什麼原因,我怎麼可能可以優化我的陳述或數據庫結構?
查詢使用哪個索引? – Jaydee
這是'EXPLAIN'顯示的內容: SIMPLE; key_event_reports; REF; report_model_id_2,get_latest_report; report_model_id_2; 4;常量; 8873835;使用索引 – Thomas
我發現這種行爲很奇怪,因爲'report_model_id_2'索引應該適合這個查詢:在第一個索引層(n)中取report_model_id 2的路徑,在第二個索引層中取所有key_event_ids(m)層,併爲每個取第三層中所有report_ts(l)的最大值。這應該是一個簡單的遍歷索引樹,所以它是O(log(n)+ log(m)+ log(l)),這不需要20秒。 – Thomas