![](/img/trans.png)
[英]Mysql query taking 20 minutes only for 11000 records. how to optimize below mysql query select query in where clause with not exists
[英]How to optimize the mysql query with more the 20 millions records
我在我的項目中使用 MySQL,並且在“mixpanel_data”表中有超過 2000 萬條記錄。
因此,當我嘗試獲取過去 6 個月的記錄時,它會中斷請求。 它只為我提供最近 5-10 天的記錄
我正在使用以下 MySQL 查詢。
SELECT `sb_users`.`id`,`sb_users`.`name`, SUM(`mixpanel_data`.duration) as timeCount,
COUNT(`mixpanel_data`.spread_id) as PageCount,`mixpanel_data`.`language`,
`mixpanel_data`.`created_at`, `mixpanel_data`.`book_name`,
`mixpanel_data`.`email`, `mixpanel_data`.`ip_address`,
`mixpanel_data`.`event_date`, `mixpanel_data`.`type`,
'Read', `mixpanel_data`.`unique_session_id`, `mixpanel_data`.`operating_system`,
`mixpanel_data`.`country`, `mixpanel_data`.`region`, `mixpanel_data`.`city`,
`mixpanel_data`.`device`, `mixpanel_data`.`browser`,
`mixpanel_data`.`browser_version`
FROM `mixpanel_data`
LEFT JOIN `sb_users` ON `mixpanel_data`.`first_name` = `sb_users`.`username`
WHERE `mixpanel_data`.`email` !=''
AND `mixpanel_data`.`created_at` Between '2019-03-24' AND '2020-03-24'
and `mixpanel_data`.`action` IN('PauseAudio')
GROUP BY `mixpanel_data`.`email`, `mixpanel_data`.`book_name` ,
`mixpanel_data`.`language`
UNION
SELECT `sb_users`.`id`,`sb_users`.`name`, SUM(`mixpanel_data`.duration) as timeCount,
COUNT(`mixpanel_data`.spread_id) as PageCount,`mixpanel_data`.`language`,
`mixpanel_data`.`created_at`, `mixpanel_data`.`book_name`,
`mixpanel_data`.`email`, `mixpanel_data`.`ip_address`,
`mixpanel_data`.`event_date`, `mixpanel_data`.`type`,
'Read', `mixpanel_data`.`unique_session_id`, `mixpanel_data`.`operating_system`,
`mixpanel_data`.`country`, `mixpanel_data`.`region`, `mixpanel_data`.`city`,
`mixpanel_data`.`device`, `mixpanel_data`.`browser`,
`mixpanel_data`.`browser_version`
FROM `mixpanel_data`
LEFT JOIN `sb_users` ON `mixpanel_data`.`first_name` = `sb_users`.`username`
WHERE `mixpanel_data`.`email` !=''
AND `mixpanel_data`.`created_at` Between '2019-03-24' AND '2020-03-24'
and `mixpanel_data`.`action` NOT IN('PlayAudio','PauseAudio')
AND `mixpanel_data`.`spread_id` !=''
GROUP BY `mixpanel_data`.`email`, `mixpanel_data`.`book_name` ,
`mixpanel_data`.`language`
我嘗試使用以下查詢更改我的查詢,但它對我不起作用。 它也打破了請求,也給了我更少的記錄。
SELECT sb_users.id,
sb_users.NAME,
Count(mixpanel_data.spread_id) AS PageCount,
SUM(CASE When action IN ('PauseAudio') Then duration Else 0 End) as total, SUM(CASE When action NOT IN ('PlayAudio', 'PauseAudio') Then duration Else 0 End) as Sectotal,
mixpanel_data.language,
mixpanel_data.created_at,
mixpanel_data.book_name,
mixpanel_data.email,
mixpanel_data.ip_address,
mixpanel_data.event_date,
mixpanel_data.type,
'Read',
mixpanel_data.unique_session_id,
mixpanel_data.operating_system,
mixpanel_data.country,
mixpanel_data.region,
mixpanel_data.city,
mixpanel_data.device,
mixpanel_data.browser,
mixpanel_data.browser_version
FROM `mixpanel_data`
LEFT JOIN sb_users
ON `mixpanel_data`.`first_name` = `sb_users`. `username`
WHERE
mixpanel_data.email != '' AND mixpanel_data.`created_at` Between '2019-03-24' AND '2020-03-24'
AND `mixpanel_data`.`spread_id` !='' GROUP BY mixpanel_data.email,
mixpanel_data.book_name,
mixpanel_data.language
我還嘗試在 first_name、username 和 created_at 列上添加索引器。 但是查詢需要很多時間(超過 15-16 秒)
有人可以幫我優化查詢嗎?
sb_users
上的這個索引可能有幫助: INDEX(username, name, id)
。
從UNION
切換到UNION ALL
應該會加快查詢速度。 但它可能會導致重復的行。
您正在獲取一年的數據; 那是桌子的百分之幾? 如果這是一個很大的百分比,那么mixpanel_data
索引就沒有用了。
除非您有UNIQUE(book_name, email, language)
否則GROUP BY
可能不合適。 對於,如果用戶從兩個不同的 ip_addresses 看同一本書怎么辦? 查詢將傳送哪個 ip_address?
假設SELECTs
之間的唯一區別是
and ma.`action` IN('PauseAudio')
相對
and ma.`action` NOT IN('PlayAudio','PauseAudio')
AND ma.`spread_id` !=''
考慮以下事項——如果您使用的是 MySQL 8.0:
WITH cte AS
SELECT ...
FROM `mixpanel_data` AS ma
LEFT JOIN `sb_users` AS su
ON ma.`first_name` = su.`username`
WHERE ma.`email` !=''
AND ma.`created_at` >= '2019-03-24'
AND ma.`created_at` < '2019-03-24' + INTERVAL 1 YEAR
SELECT * FROM cte
WHERE `action` IN('PauseAudio')
UNION ALL
SELECT * FROM cte
WHERE `action` NOT IN('PlayAudio','PauseAudio')
AND `spread_id` !=''
GROUP BY `email`, `book_name` , `language`
希望這會導致只掃描mixpanel_data
一次。
另一種方法(不依賴於 8.0):有一個內部查詢(“派生表”),它使用mixpanel_data
完成工作,然后JOIN
sb_users
:
SELECT ...
FROM ( SELECT ...
FROM mixpanel_data
-- (no JOIN)
WHERE ...
GROUP BY ...
UNION ALL
FROM mixpanel_data
-- (no JOIN)
WHERE ... (the other)
GROUP BY ...
)
LEFT JOIN sb_users ON ...
這樣做的好處是它不會在所有工作中都拖着 sb_user 數據。 相反,它在通過GROUP BY
縮小行數后從 sb_user 獲取。
可能還有更多提示; 請執行上述一些操作,然后提供EXPLAIN SELECT
和一些表大小。
這是第一個查詢。 第二個查詢在幾個方面有所不同:
spread_id
的測試UNION
的重復數據刪除可能會導致一組不同的行。 我對建議JOINing
到sb_users
做后GROUP BY
在這里也適用(雖然沒有UNION
)。
調試
SELECT ... FROM mixpanel_data
沒有SUM
、 COUNT
和GROUP BY
,但添加一個LIMIT
。 查看數據是否符合您的預期。SUM
、 COUNT
和GROUP BY
; 關注那些結果。JOIN
到另一個表。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.