我有一个名为test的表:
create table demo (name varchar(10), mark1 int, mark2 int);
我需要多次为每一行提供mark1和mark2的总和。
select name, (mark1 + mark2) as total from demo;
我被告知效率不高。我不允许在表格中添加新的总列。
我可以在Index中存储这样的业务逻辑吗?
我创建了一个视图
CREATE VIEW view_total AS SELECT name, (mark1 + mark2) as 'total' from demo;
我用:
填充了演示表DELIMITER $$
CREATE PROCEDURE InsertRand(IN NumRows INT)
BEGIN
DECLARE i INT;
SET i = 1;
START TRANSACTION;
WHILE i <= NumRows DO
INSERT INTO demo VALUES (i,i+1,i+2);
SET i = i + 1;
END WHILE;
COMMIT;
END$$
DELIMITER ;
CALL InsertRand(100000);
执行时间
select * from view_total;
和
select * from demo;
相同,10毫秒。所以我没有从视角中获益。我尝试使用以下方法在视图上创建索引:
create index demo_total_view on view_total (name, total);
失败但错误:
ERROR 1347 (HY000): 'test.view_total' is not BASE TABLE
关于如何防止累计列的冗余操作的任何指针?
答案 0 :(得分:5)
作为一般规则,从不存储在表中,您可以在退出时计算出来。例如,你想要年龄,你应该存储出生日期。如果你想要两列的总和,你应该存储这两列,没有别的。
维护数据库中的数据完整性,质量和一致性应该是您最关心的问题。如果第三列(即前两个列的总和)可能不同步,那么它就不值得做了。
由于无法在不将计算嵌入到将数据插入表中的所有代码(未来会被遗忘并且更新可能会破坏它)或每次插入某些内容时触发计算(大量额外工作)都无法维护列你不应该这样做。
您的情况是观看的完美用例。您需要以相同的方式一致地计算列。如果你让每个人都按照自己的意愿计算出来,那么就会出现与插入计算列相同的问题,你需要保证始终以相同的方式计算。这样做的方法是在桌面上创建一个以标准方式预先计算列的视图,对每个用户都是相同的。
计算数百个时间的总和会比从某个地方读取它要贵得多......对吗?
不一定,这完全取决于您自己的情况。如果你有较慢的磁盘,那么读取数据可能比计算它更容易。特别是因为它是一个非常简单的计算。
它很可能根本不会产生任何差别,但如果它是一个主要的性能问题,你应该测试这两种情况,并决定数据质量的潜在损失和维持表中计算的额外开销是否值得从数据库中提取奇数纳秒。
答案 1 :(得分:3)
我被告知效率不高。
由谁?当然你应该要求发表声明的人解释它 - 而不是我们?
效率怎么样? 仅时间会影响性能显着,您可以在mark1和/或mark2上使用索引 - 它不会用于以下查询:< / p>
SELECT *
FROM demo
WHERE mark1+mark2 > 200;
但是对于这两个值的索引,您可以这样做:
SELECT *
FROM demo
WHERE mark1+mark2 > 200
AND (mark1 > (200/2) OR mark2 > (200/2));
将2列添加到一起的开销可以忽略不计。你可以通过测量比较经过的时间来证明这一点:
SELECT SQL_NO_CACHE mark1, mark2, name FROM demo;
和
SELECT SQL_NO_CACHE mark1+mark2, name FROM demo;
(关于你的错误 - 如果在表上创建索引,那么视图将自动检测并使用它。)
(MariaDB支持virtual columns,可用于创建Oracle基于函数的索引等行为。