题
假设我有两个这样的表:
Employers (id, name, .... , deptId). Depts(id, deptName, ...).
但是这些数据不会经常修改,我想要这样的查询
SELECT name, deptName FROM Employers, Depts
WHERE deptId = Depts.id AND Employers.id="ID"
尽可能快。
我想到了两种可能的解决方案:
对表进行非规范化:
尽管使用这个解决方案,我将失去“标准化数据库”的一些巨大优势,但这里的性能是必须的。
为非规范化数据创建一个视图。
我将保持数据标准化并且(这是我的问题),对该视图的查询性能将比没有该视图时更快。
或者用另一种方式提出同样的问题,每次对视图进行查询时,视图都会被“解释”,或者 DBA 中的视图内容如何工作?
解决方案
通常,除非您“具体化”视图(这是某些软件(如 MS SQL Server)中的一个选项),否则视图只是转换为针对基表的查询,因此不会比原始视图更快或更慢(减去极少量的数据)翻译查询所花费的时间,与实际执行查询相比根本不算什么)。
你怎么知道你有性能问题?您是否在负载下对其进行分析?你验证过性能瓶颈是这两个表吗?一般来说,在获得硬数据之前,不要假设您知道性能问题从何而来,也不要花任何时间进行优化,直到您知道正在优化正确的内容 - 80% 的性能问题来自 20代码的%。
其他提示
如果 Depts.ID 是该表的主键,并且您对 Employers.DeptID 字段建立索引,那么即使在数百万条记录上,此查询也应该保持非常快的速度。
在这种情况下,非规范化对我来说没有意义。
一般来说,视图的性能与运行查询本身时的性能几乎完全相同。视图的优点是简单地抽象出该查询,因此您不必考虑它。
您可以使用物化视图(或某些人所说的“快照”),但是您的数据只会是上次刷新时的最新数据。
在对其中一个回复的评论中,问题的作者解释说,他正在寻找一种在 MySQL 中创建物化视图的方法。
MySQL 不像其他 DBMS 那样将物化视图的概念包装在一个很好的包中,但它确实拥有创建物化视图所需的所有工具。
你需要做的是这样的:
- 创建查询结果的初始具体化。
- 在插入雇主表时创建一个触发器,将与新插入的雇主匹配的所有行插入到具体化表中。
- 在雇主表中创建删除触发器,从物化表中删除相应的行。
- 在雇主表中创建更新触发器,以更新具体化表中的相应行。
- 部门表也是如此。
如果您的基础表不经常更新,这可能会起作用;但一旦执行此操作,您需要注意创建/更新/删除操作的额外成本。此外,您还需要确保一些不知道您的诡计的 DBA 在时机到来时不会在没有迁移触发器的情况下迁移数据库。所以要好好记录一下。
听起来像是过早的优化,除非您知道这是一个明确且当前的问题。
MySQL 不会具体化视图,它们并不比针对基表的查询快。此外,在某些情况下,它们会变慢,因为它们优化得不太好。
但是视图也会向将来维护代码的开发人员“隐藏”一些东西,使他们认为查询并不像实际那样复杂。