簡體   English   中英

MySQL慢查詢優化國家百分比查​​詢

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM