我在我的 mariaDB 数据库中得到了一个视图“project_sum”。该视图有 4 个有问题的列,其中每个列都计算accounting_records 的总和。其中每个值总计最多 200 个accounting_records。
最终视图总共大约有 5000 行。因此它必须计算大约 5.000x200 个accounting_record 值的 5.000x4 总和。
这是视图的查询:
DROP VIEW IF EXISTS project_sum;
CREATE VIEW project_sum AS
SELECT
project_id,
SUM(CASE
WHEN planned_actual_indicator = 'planned' AND datev_type = 'incoming'
THEN (value_in_euro)
ELSE 0
END
) AS 'sum_incoming_planned',
SUM(CASE
WHEN planned_actual_indicator = 'actual' AND datev_type = 'incoming'
THEN (value_in_euro)
ELSE 0
END
) AS 'sum_incoming_actual',
SUM(CASE
WHEN planned_actual_indicator = 'planned' AND datev_type = 'outgoing'
THEN (value_in_euro)
ELSE 0
END
) AS 'sum_outgoing_planned',
SUM(CASE
WHEN planned_actual_indicator = 'actual' AND datev_type = 'outgoing'
THEN (value_in_euro)
ELSE 0
END
) AS 'sum_outgoing_actual'
FROM accounting_record USE INDEX (is_initial)
WHERE accounting_record.is_initial = false
GROUP BY project_id;
不幸的是,打开视图时,总和需要始终是最新的。对错误价值观采取零容忍政策,因为这与金钱有关。 因此,我们必须即时计算总和,并且不能将预先计算的结果存储在数据库表中。这使得页面加载速度非常慢,加载性能非常差。
我的一个想法是每次推送新的accounting_record时更新预先计算的总和,但后来我们考虑了竞赛条件,这可能最终导致一个总和缺少同时添加的另一条记录的值。
我们已经对我们汇总的记录的键建立了索引:is_initial、planned_actual_indicator甚至datev_type和project_id。但这也没有多大帮助。有没有办法改进这个查询,使性能更好?
您还没有告诉我们任何有关您的表结构或索引的有用信息,因此这是猜测。
摆脱
USE INDEX
。甚至Monty Widenius也没有使用它。
创建复合覆盖索引...
ALTER TABLE accounting_record
ADD INDEX viewcover
( is_initial, project_id,
planned_actual_indicator, datev_type,
value_in_euro)
应该可以通过对该索引进行顺序索引范围扫描来生成结果集。这将节省大量的 IO 和临时表排序步骤,这应该会有所帮助。
但请注意,此视图中的查询必须处理表中很大一部分行。没有任何奇怪的 SQL 巫术可以使它比 O(n) 更快。因此,明智的做法是降低用户的期望。