数据库
首页 > 数据库> > mysql-关系数据库(RDBMS)非规范化数据

mysql-关系数据库(RDBMS)非规范化数据

作者:互联网

我相信这个问题并没有专门针对MySQL-我正在使用的数据库-,而是关于最佳实践的问题.

到目前为止,我的问题可以通过创建表和查询表(有时在这里和那里联接)来解决.但是我正在做的事情感觉不对劲,每当我需要在我的“常见”查询旁边加上非规范化数据时,就会触发我.

示例用例

为了让我更好地表达自己,让我们创建一个肤浅的场景,其中:

>用户可以购买产品并产生购买(让我们忽略购买只能有一个产品这一事实);
>并且我们需要查询产品的购买总次数;

为了解决用例,我们可以定义一个简单的结构,该结构由:

>产品表:

> product_id [INT PK]

>用户表:

> user_id [INT PK]

>购买表:

> Purchase_id [INT PK]
> product_id [INT FK NOT NULL]
> user_id [INT FK不为空]

这是不对劲的地方:当我们需要检索具有购买总次数的产品列表时,我将创建查询:

# There are probably faster queries than this to reach the same output
SELECT
    product.product_id,
    (SELECT COUNT(*) FROM purchase
      WHERE purchase.product_id = product.product_id)
FROM
    product

我担心的原因是,我已经阅读到COUNT会进行全表扫描,并且当我缩放到要购买的数千种产品时,即使在购买时我已经用product_id FK创建了一个INDEX( MySQL默认执行此操作.

可能的解决方案

我对关系数据库的了解还很浅,因此在比较这些问题的替代方案(合理的替代方案)时,我有点迷失了.不用说我还没有做完作业(在询问之前先搜索),我发现可以这样做:

创建交易:

插入新购买商品时,它必须始终位于事务中,该事务还将使用purchase.product_id更新产品表.

可能的问题:人为错误.有人可能不进行交易和BAM而手动插入了购买商品-我们存在不一致之处.

创建触发器:

每当我插入,删除或更新某些特定表中的某些行时,我都会使用新值(bought_amount)更新我的产品表.因此表将变为:

>产品表:

> product_id [INT PK]
> buy_amount [INT NOT NULL];

可能的问题:触发器昂贵吗?有没有一种方法可以成功插入但触发器不会成功-从而使我前后不一致?

更新某些表以存储不断变化的数据是RDBMS的一种可行方法吗?长期加入并计数/求和其他事件是否更安全,并且从长远来看更有利?

我发现了一些有关此问题的有用问题/答案,但没有一个能广泛地解决这个问题.
请考虑我对RDBMS的无知,因为我可能会建议废话.

解决方法:

获取每个键计数的通常方法是

SELECT product_id, COUNT(*)
FROM purchase
GROUP BY product_id

您不需要提及产品表,因为它包含的只是键列.现在,尽管它使用COUNT(*),但是它不需要为每个product_id进行全表扫描,因为SQL引擎足够聪明,可以看到GROUP BY.

但这会产生与您的查询不同的结果:对于从未购买过的产品,我的查询根本不会显示它们;您的查询将显示带有零计数的product_id.

然后,在您开始担心实施和效率问题之前,您要尝试回答哪些问题?如果要查看是否购买了所有产品,则必须扫描整个产品表并从中查找要购买的产品.我会去

SELECT product_id, count
FROM product
OUTER JOIN (SELECT product_id, COUNT(*) AS count
            FROM purchase
            GROUP BY product_id) AS purch
ON product.product_id = purch.product_id

关于您的更广泛的问题(不确定我是否完全理解它们),在早期,SQL在这种连接和聚合方面效率很低,并且架构经常在多个表中使用重复的列进行非规范化. SQL引擎现在更加智能,因此没有必要.您可能会在较旧的教科书中看到这种过时的做法.我会忽略它,并设计您的架构尽可能规范化.

标签:database-design,query-optimization,relational-database,mysql
来源: https://codeday.me/bug/20191108/2005181.html