如何使用超过2000万条记录优化mysql查询
我在项目中使用MySQL,在mixpanel_数据表中有超过2000万条记录 因此,当我试图获取过去6个月的记录时,它会破坏请求。它只向我提供最近5-10天的记录 我正在使用以下MySQL查询如何使用超过2000万条记录优化mysql查询,mysql,sql,indexing,Mysql,Sql,Indexing,我在项目中使用MySQL,在mixpanel_数据表中有超过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_da
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 column上添加索引器。但是查询需要花费的时间超过15-16秒
有人能帮我优化查询吗?此索引对sb\U用户可能有帮助:INDEXusername、name、id
从UNION切换到UNION ALL应该可以加快查询速度。但这可能会导致重复的行
您正在获取一年的数据;那占桌子的百分比是多少?如果这是一个很大的百分比,那么没有关于mixpanel_数据的索引是有用的
除非您有UNIQUEbook_名称、电子邮件和语言,否则“分组方式”可能不合适。例如,如果用户从两个不同的ip_地址查看同一本书,该怎么办;查询将传递哪个ip_地址
假设选择之间的唯一差异是
对
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`
这样做的好处是,它不会在整个工作过程中拖拉sb_用户数据。相反,它是在通过GROUPBY减少行数后从sb_用户获取的
可能会有更多的提示;请完成上面的一些操作,然后提供解释选择和一些表格大小
这是第一个问题。第二个查询在两个方面有所不同:
缺少对扩展id的测试
联合的重复数据消除可能会导致一组不同的行。
虽然没有工会,但我关于在完成分组后加入sb_用户的建议也适用于这里
调试
选择从mixpanel_数据,不包含总和、计数和分组依据,但添加限制。看看数据是否与您期望的一样。
添加总和、计数和分组依据;仔细观察这些结果。
然后连接到另一个表。
你说它违背了要求是什么意思。?然后只发送部分结果?听起来不对。你的查询无效。您可以通过电子邮件、书名、语言进行分组,但可以选择浏览器版本作为示例。组的哪个浏览器版本?最伟大的?最小的?事件的日期、类型、区域等也是如此。由于您似乎正在努力解决聚合组的概念,我建议您将sql模式设置为“仅完整组”;以帮助您构建有效的查询。如果没有该设置,MySQL将通过返回任意值来规避查询的缺陷,这通常意味着不需要的结果。如果您希望每个组的浏览器版本、类型等相同,那么您的数据模型甚至会出现问题,应该在编写任何查询之前对其进行规范化。
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`
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 ...