[英]MySQL query is too slow, how can I improve this?
我有這個查詢,在一個約300.000行的表上需要大約14秒來提取數據。 該表將在不久的將來增加其規模......超過一百萬行。 我使用了EXISTS
子句而不是IN
子句,並且我給了一個改進。 但查詢太慢了。 你有解決方案嗎? 提前致謝。
這是查詢:
SELECT
flow,
COUNT(*) tot
FROM
(
SELECT
ff.session_id,
GROUP_CONCAT(ff.page, '#', ff.snippet_params,'$',ff.is_lead SEPARATOR '|') flow
FROM table_a ff
WHERE EXISTS
(
SELECT
f.session_id
FROM table_a f
WHERE f.session_id = ff.session_id
AND f.is_lead = 1
GROUP BY f.user_id
ORDER BY f.user_id, f.`timestamp`
)
GROUP BY ff.user_id
ORDER BY ff.user_id, ff.`timestamp`, ff.session_id
)
AS flow
GROUP BY flow
ORDER BY tot DESC LIMIT 10
這是解釋:
id select_type table type possible_keys key key_len ref rows Extra
------ ------------------ ---------- ------ ------------------ ---------- ------- ----------------------------- ------ ----------------------------------------------
1 PRIMARY <derived2> ALL (NULL) (NULL) (NULL) (NULL) 532 Using temporary; Using filesort
2 DERIVED ff ALL (NULL) (NULL) (NULL) (NULL) 322154 Using temporary; Using filesort
3 DEPENDENT SUBQUERY f ref is_lead,session_id session_id 767 ff.session_id 3 Using where; Using temporary; Using filesort
ORDER BY中的額外表達式沒有任何意義,因為“ GROUP BY user_id
”將保證user_id
的唯一值。
ORDER BY
操作在GROUP BY
操作之后應用。 如果我的目的是獲得每個user_id
的最低session_id
,我會使用MIN
聚合。 在原始查詢中, ORDER BY
對返回的session_id
沒有任何影響。 為session_id
返回的值是不確定的。
(其他數據庫會在此查詢中引發錯誤。對GROUP BY的特定於MySQL的擴展允許查詢運行,但我們可以通過在sql_mode中包含ONLY_FULL_GROUP_BY來獲得更多標准行為。)
EXISTS子查詢中的GROUP BY
沒有任何意義。 如果找到row,則存在一行。 無需執行GROUP BY並聚合找到的行。
並且更仔細地查看它,似乎沒有必要在SELECT列表中返回session_id
。 (在flow
視圖查詢中,或在EXISTS子查詢中。)
如果我們刪除無關的語法並將查詢簡化為其本質,那么對於實際上重要的部分,我們將留下如下所示的查詢:
SELECT flow.flow AS flow
, COUNT(*) AS tot
FROM (
SELECT GROUP_CONCAT(ff.page,'#',ff.snippet_params,'$',ff.is_lead SEPARATOR '|') AS flow
FROM table_a ff
WHERE EXISTS
( SELECT 1
FROM table_a f
WHERE f.is_lead = 1
AND f.session_id = ff.session_id
)
GROUP BY ff.user_id
) flow
GROUP BY flow.flow
ORDER BY tot DESC
LIMIT 10
查詢基本上說來擺脫(在不幸命名表)中的所有行table_a
其中有一個session_id
相匹配的至少一個排table_a
具有相同價值session_id
其中也有is_lead
值1。
然后獲取所有找到的行,並根據user_id
列中的值聚合它們。
在GROUP_CONCAT中沒有ORDER BY是很奇怪的,而且有點奇怪的是沒有DISTINCT關鍵字。
GROUP_CONCAT聚合返回行的不確定順序並且還可能包含重復值,這很奇怪。 (假設外部查詢將基於從GROUP_CONCAT聚合返回的值執行另一個聚合。)
但是,我不確定這個查詢應該回答什么問題。 而且我不知道什么是獨特的,什么不是。
我們知道EXISTS子查詢可以重寫為JOIN操作:
SELECT flow.flow AS flow
, COUNT(*) AS tot
FROM (
SELECT GROUP_CONCAT(ff.page,'#',ff.snippet_params,'$',ff.is_lead SEPARATOR '|') AS flow
FROM ( SELECT d.session_id
FROM table_a d
WHERE d.is_lead = 1
GROUP BY d.session_id
) e
JOIN table_a ff
ON ff.session_id = e.session_id
GROUP BY ff.user_id
) flow
GROUP BY flow.flow
ORDER BY tot DESC
LIMIT 10
我們可以努力使查詢運行得更快。 但在我這樣做之前,我想確保查詢返回一個與規范匹配的集合。 我需要確保查詢實際上回答了它旨在回答的問題。
我懷疑原始查詢不正確。 也就是說,我認為如果查詢返回“正確”的結果,它會意外地這樣做,而不是因為它保證了。 或者因為表中行的唯一性(基數)或者由於處理行的意外順序而存在特殊情況。
我想確保查詢保證在我花時間調整它並添加索引之前返回正確的結果。
問:為什么GROUP_CONCAT
沒有ORDER BY
? 例如
GROUP_CONCAT( foo ORDER BY something)
問:是否有特定原因沒有DISTINCT關鍵字?
GROUP_CONCAT(DISTINCT foo ORDER BY something)
問:我們是否應該關注GROUP_CONCAT(靜默)返回截斷值的可能性? (基於group_concat_max_length
變量的設置?)
跟進
為了在上面的答案中最后一個查詢的最佳性能,我建議添加以下索引:
... ON table_a (session_id, is_lead, page, snippet_params)
或者任何類似的索引,將session_id
和is_lead
作為前導列( is_lead
順序),還包括page
和snippet_params
列。 如果將ORDER BY添加到GROUP_CONCAT,我們可能需要稍微不同的索引。
對於外部查詢,導出的flow
列沒有繞過“使用filesort”操作。 (除非您運行的是更新版本的MySQL,其中可能會創建索引。或者我們可以將查詢分解為兩個單獨的操作。一個查詢將內聯視圖實現為表,第二個查詢運行對此。)
在此子查詢中,您使用的是group by但沒有聚合函數。
對於基於組合或不具有f.session_id
結果的EXIST的檢查是相同的..你應該刪除組和順序
WHERE EXISTS
(
SELECT
f.session_id
FROM table_a f
WHERE f.session_id = ff.session_id
AND f.is_lead = 1
GROUP BY f.user_id
ORDER BY f.user_id, f.`timestamp`
)
這條路
WHERE EXISTS
(
SELECT
f.session_id
FROM table_a f
WHERE f.session_id = ff.session_id
AND f.is_lead = 1
)
查看您的查詢我認為可以重構,例如:
SELECT flow , COUNT(*) tot
FROM (
select
GROUP_CONCAT(ff.page, '#', ff.snippet_params,'$',ff.is_lead SEPARATOR '|') flow ,
FROM table_a ff
WHERE f.is_lead = 1
GROUP BY ff.user_id ) as new_flow
GROUP BY flow
ORDER BY tot DESC LIMIT 10
您需要確保將f.session_id和f.is_lead編入索引。 它目前正在針對table_a的ff引用對中間結果中的每一行執行f的表掃描。
很難給出這個查詢(或這些查詢)的優化版本。 您可能不想更改數據庫結構,因此它允許更簡單的查詢。 也許是其他值的一些緩存(redis等)......
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.