0

我有一个名为 test 的表:

create table demo (name varchar(10), mark1 int, mark2 int);

我多次需要每一行的 mark1 和 mark2 的总数。

select name, (mark1 + mark2) as total from demo;

我被告知效率不高。我不允许在表中添加新的总计列。

我可以在索引中存储这样的业务逻辑吗?

我创建了一个视图

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

关于如何防止总计列的冗余操作的任何指针?

4

2 回答 2

5

作为一般规则,永远不要将退出时可以计算的内容存储在表格中。例如,您想要年龄,您应该存储出生日期。如果您想要两列的总和,则应该存储这两列,仅此而已。

维护数据库中的数据完整性、质量和一致性应该是您最关心的问题。如果第三列(即前两列的总和)有微小的可能不同步,那么就不值得这样做。

因为如果不将计算嵌入到将数据插入表中的所有代码中(将来容易被遗忘并且更新可能会破坏它)或每次插入某些内容时触发触发器(大量额外工作),您就无法维护列不要这样做。

您的情况是视图的完美用例。您需要以相同的方式一致地计算一列。如果您让每个人都按照自己的意愿进行计算,那么会出现与插入计算列相同的问题,您需要保证始终以相同的方式计算。做到这一点的方法是在您的表上有一个以标准方式预先计算列的视图,这对于每个用户都是相同的。

计算数百次的总和会比从某个地方读取它要昂贵得多......对吗?

不一定,这完全取决于你自己的情况。如果您的磁盘速度较慢,那么读取数据可能会比计算数据更昂贵。特别是因为这是一个非常简单的计算。

很可能它根本不会产生任何影响,但如果这是一个主要的性能问题,您应该测试这两种情况并确定数据质量的潜在损失和维护表中计算的额外开销是否值得奇怪的纳米其次是从数据库中提取。

于 2013-02-18T13:25:53.373 回答
3

我被告知效率不高。

通过谁?当然,您应该要求发表声明的人解释它 - 而不是我们?

效率不高怎么办?唯一显着影响性能的地方是您可以在 mark1 和/或 mark2 上使用索引 - 它不会用于如下查询:

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 支持虚拟列,可用于创建类似于 Oracle 的基于函数的索引的行为)。

于 2013-02-18T13:47:45.997 回答