mysql - 大表的 MySQL 优化
问题描述
如果需要,我可以添加更多详细信息,但基本上会遇到查询大表(1 亿多行)的问题。我的查询需要几分钟才能完成。大部分数据是以前的数据(即去年的销售数据),不会改变。我已经在我制作的其他报告中使用了这些数据,并且能够每晚将数据“汇总”到一个按月、年等分组的新表格中。但是,在我正在构建的报告中,有很多动态的诸如自定义时间/日期选择器之类的元素,这使我很难进行此类汇总。
我想我的问题是,有没有人对大表和动态查询有很多经验?
我也尽我所能完成了我的研究,我还确保我的数据库装备精良。目前 16gb 内存和 12gb InnoDB 缓冲池。(我不是这里的专家,所以让我知道是否还有其他需要寻找的东西)。
感谢任何人的帮助,如果您想了解我的用例的具体信息,请再次告诉我。
SELECT mainaccounts.account_id AS 'ACCOUNTID',
(
SELECT name
FROM activitysettings
WHERE org_id = '5a1da86ed6ea7c6000e45e82'
AND id = '5a1da86ed6ea7c6000e45e8e' ) AS 'ACTIVITYNAME',
(
SELECT Count(DISTINCT a.id)
FROM activity a
WHERE a.org_id = '5a1da86ed6ea7c6000e45e82'
AND (
a.started_at BETWEEN '2018-01-01' AND '2018-02-01')
AND a.status = true
AND a.account_id = mainaccounts.account_id
GROUP BY a.account_id ) AS 'ACTIVITYTHIS',
(
SELECT Count(DISTINCT b.id)
FROM activity b
WHERE b.org_id = '5a1da86ed6ea7c6000e45e82'
AND (
b.started_at BETWEEN '2017-01-01' AND '2017-02-01')
AND b.status = true
AND b.account_id = mainaccounts.account_id
AND b.activity_id = '5a1da86ed6ea7c6000e45e8e'
GROUP BY b.account_id ) AS 'ACTIVITYLAST',
ifnull(
(
SELECT Sum(s1.volumece)
FROM sales s1
WHERE s1.org_id = '5a1da86ed6ea7c6000e45e82'
AND (
s1.invoice_date BETWEEN '2018-01-01'AND '2018-02-01'
AND s1.status = true
AND s1.account_id = mainaccounts.account_id group BY s1.account_id ),
0) AS 'SALESTHIS', ifnull(
(
SELECT sum(s2.volumece)
FROM sales s2
WHERE s2.org_id = '5a1da86ed6ea7c6000e45e82'
AND (
s2.invoice_date BETWEEN '2017-01-01' AND '2017-02-01'
AND s2.status = TRUE
AND s2.account_id = mainaccounts.account_id GROUP BY s2.account_id ),
0) AS 'SALESLAST', @podthis := ifnull(
(
SELECT sum(s1.units)
FROM sales s1
WHERE s1.org_id = '5a1da86ed6ea7c6000e45e82'
AND (
s1.invoice_date BETWEEN '2018-01-01'AND '2018-02-01'
AND s1.status = TRUE
AND s1.account_id = mainaccounts.account_id GROUP BY s1.account_id ),
0) AS 'UNITSTHIS', @podlast :=ifnull(
(
SELECT sum(s2.units)
FROM sales s2
WHERE s2.org_id = '5a1da86ed6ea7c6000e45e82'
AND (
s2.invoice_date BETWEEN '2017-01-01' AND '2017-02-01')
AND s2.status = TRUE
AND s2.account_id = mainaccounts.account_id
GROUP BY s2.account_id ),0) AS 'UNITSLAST',
CASE
WHEN (
@podthis IS NULL
OR @podthis <= 0) THEN 0
ELSE 1
end AS 'ISPODTHIS',
CASE
WHEN (
@podlast IS NULL
OR @podlast <= 0) THEN 0
ELSE 1
end AS 'ISPODLAST' FROM activity mainaccounts WHERE
mainaccounts.org_id = '5a1da86ed6ea7c6000e45e82'
AND mainaccounts.started_at BETWEEN '2018-12-01' AND
'2018-12-31'
AND mainaccounts.status = TRUE
AND mainaccounts.activity_id = '5a1da86ed6ea7c6000e45e8e'
GROUP BY account_id
我有很多索引,所以请询问是否有您认为需要或有帮助的特定索引。
解决方案
汇总应该是当天的。这让任何日期范围都可以通过汇总汇总表来工作。
至于其他“动态”的东西,您需要已经构建包含可能的动态列的汇总表,并在汇总表上提供“足够的”索引。然后在 UI 中添加一些智能来选择适当的摘要表。
根据我的经验(您所描述的几个项目),选择摘要表中需要的列总是相当容易,甚至可以定制 UI 页面以引导用户选择可用的选项。偶尔会有一个新的请求进来;然后我编写新代码将原始数据汇总到一个新的摘要表中(或扩充现有的表),生成一个 UI,然后工作就完成了。
更多讨论
附带问题...
涉及什么
index2
以及涉及哪些数据类型?我担心func
在解释。范围
在“2017-01-01”和“2017-02-01”之间开始
如果目标是 a DATE
,您有 32 天。如果是DATETIME
,则您有 31 天加一秒(额外的午夜)。我推荐这种模式;它适用于所有日期类型,并避免闰年(等)的麻烦:
started_at >= '2017-01-01'
AND started_at < '2017-01-01' + INTERVAL 1 MONTH
- 索引
主账户是否有
INDEX(org_id, status, activity_id, -- in any order
started_at) -- after the others
也就是说,先有=
s,然后是“范围”。
活动需求
INDEX(org_id, status, account_id, activity_id, -- in any order, then
started_at)
推荐阅读
- sml - 是什么导致我的 SML 变量未绑定?
- python - 如何防止第二个for循环减慢服务返回的数据
- gstreamer - 使用 udp 启动 rtp
- windows - 如何处理勺子错误:Redis 中的权限被拒绝
- jquery - jQuery:如何打开一个新的模态对话框或弹出窗口
- mongodb - 将 MongoDB 从 root 更改为 Sudo 用户
- testing - 带有 Electron 的 TestCafe:无法加载主页(主页可能返回“304”http 代码)
- php - SQL 选择 - 多个孩子
- angular - Bootstrap Angular Stepper 的材料设计不起作用
- sql - 如何获取层次结构表中所有记录的父级?