[英]MySQL slow query optimize countries percentage query
此查詢需要100秒才能運行。 我已將每個用於條件或連接的列編入索引,但運行時間太長。 如何以有效運行的方式編寫此查詢?
SELECT e.earning_country, c.country_name, COUNT(e.earning_id) AS views, ROUND(100 * COUNT(e.earning_id)/b.total, 2) AS percentage
FROM earnings AS e
CROSS JOIN (
SELECT COUNT(earning_id) AS total
FROM earnings
WHERE earning_paid = 1 AND earning_ad_id = 1 AND earning_referral_id = 0) AS b
INNER JOIN countries as c
ON c.country_id = e.earning_country_id
WHERE earning_paid = 1 AND e.earning_ad_id = 1 AND earning_referral_id = 0
GROUP BY e.earning_country
ORDER BY percentage DESC
解釋結果:
"id", "select_type", "table", "type", "possible_keys", "key", "key_len", "ref", "rows", "Extra"
1, "PRIMARY", "<derived2>", "system", NULL, NULL, NULL, NULL, 1, "Using temporary; Using filesort"
1, "PRIMARY", "e", "index_merge", "earning_referral_id_index,earning_country_id_index,earning_paid_index,earning_ad_id_index", "earning_referral_id_index,earning_paid_index,earning_ad_id_index", "4,1,4", NULL, 362698, "Using intersect(earning_referral_id_index,earning_paid_index,earning_ad_id_index); Using where"
1, "PRIMARY", "c", "eq_ref", "PRIMARY", "PRIMARY", 4, "site.e.earning_country_id", 1, NULL
2, "DERIVED", "earnings", "index_merge", "earning_referral_id_index,earning_paid_index,earning_ad_id_index", "earning_referral_id_index,earning_paid_index,earning_ad_id_index", "4,1,4", NULL, 362698, "Using intersect(earning_referral_id_index,earning_paid_index,earning_ad_id_index); Using where; Using index"
這不是一個真正的答案,但請嘗試運行以下查詢以了解您以簡單的方式處理此數據的速度:
SELECT
e.earning_country
,c.country_name
-- ,COUNT(e.earning_id) AS views
FROM earnings AS e
INNER JOIN countries as c
ON c.country_id = e.earning_country_id
WHERE earning_paid = 1 AND e.earning_ad_id = 1 AND earning_referral_id = 0
GROUP BY e.earning_country_id
;
嘗試使用views
行進行注釋和運行來運行它,並查看性能上的差異,注意:我注意到您在原始查詢中通過earning_country
而不是earning_country_id
進行分組。
PS - 如果此查詢運行得更快,您可以在內存中完成剩余的計算以獲得總計,百分比並對其進行排序。
如果您想了解三向索引的大小,請嘗試運行查詢:
SELECT
COUNT(DISTINCT earning_paid, earning_ad_id, earning_referral_id)
FROM earnings;
索引大小應基於數據的可變性,而不是表的大小。
如果earning_id
永遠不是NULL
(並且主鍵不應該是),那么您可以通過使用COUNT(*)
而不是COUNT(earning_id)
來提升性能。
MySQL每個表只使用1個索引。 所以你有4列的索引用於where子句和連接只會使用其中一個索引。 MySQL會選擇它認為最好的索引,但這可能遠非完美。
使用您的查詢我懷疑earning_paid是一個標志,所以它本身可能對索引很少使用(平均一半的記錄將具有每個值)。 使用earning_ad_id和earning_referral_id,您似乎正在檢查0,這是我假設每個的默認值,並且每個可能再次覆蓋大量行。 將這3個組合在一起可能確實有一些用作索引。
earning_country可能作為聚合函數的索引很有用,但無法縮小行數。
如果您有一個涵蓋所有4列的索引,那么可以使用它
設置覆蓋earning_paid,earning_ad_id,earning_referral_id和earning_country(按此順序)的索引。
編輯
小解釋
假設你有一本電話簿。 要查找名稱,這是按姓氏排序的(實際上是一個索引)。 滾動瀏覽直到找到所需的名稱,按名稱順序這很容易。
如果你想找一個名叫史密斯的人,你可以快速跳到那里。
如果您知道他們的名字,那么您可以在史密斯列表中輕松找到它。 所以可以找到約翰史密斯(無疑很多)。
但是,如果你想找一個叫史密斯的醫生而你不知道他們的名字,你就可以在姓氏和頭銜上找到一個索引。 如果它是一個罕見的姓氏和一個共同的頭銜,最好是姓氏第一和頭銜第二,如果姓氏是常見的並且標題很少,那么最好將頭銜和姓氏列為第二。
在這種情況下,索引只是每個姓氏和標題的列表,並帶有指向記錄其余部分的指針。
如果你想要一個名為史密斯的所有醫生的計數,那么你可以只需查看索引而不需要查看記錄的其余部分。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.