【发布时间】:2023-03-11 00:05:01
【问题描述】:
我正在开发一个越来越受欢迎的移动网站,这导致一些关键数据库表的增长 - 我们开始在访问这些表时看到一些性能问题。不是数据库专家(现阶段也没有钱聘请任何人),我们正在努力了解导致性能问题的原因。我们的表没有那么那么大,因此 SQL Server 应该能够很好地处理它们,并且我们已经完成了我们在优化查询方面所知道的一切。所以这是(伪)表结构:
[user] (approx. 40,000 rows, 37 cols):
id INT (pk)
content_group_id INT (fk)
[username] VARCHAR(20)
...
[content_group] (approx. 200,000 rows, 5 cols):
id INT (pk)
title VARCHAR(20)
...
[content] (approx. 1,000,000 rows, 12 cols):
id INT (pk)
content_group_id INT (fk)
content_type_id INT (fk)
content_sub_type_id INT (fk)
...
[content_type] (2 rows, 3 cols)
id INT (pk)
...
[content_sub_type] (8 rows, 3 cols)
id INT (pk)
content_type_id INT (fk)
...
我们预计这些行数会大幅增长(尤其是 user、content_group 和 content 表)。是的,用户表有很多列——我们已经确定了一些可以移动到其他表中的列。我们还对受影响的表应用了一些索引,这些索引也有所帮助。
最大的性能问题是我们用于搜索用户的存储过程(包括在 content_group_id 字段上连接到内容表)。我们尝试使用各种不同的方法修改 WHERE 和 AND 子句,我们认为我们已经尽可能地完善它们,但仍然太慢了。
我们尝试过的另一件没有帮助的事情是在用户表和内容表上放置一个索引视图。当我们这样做时没有明显的性能提升,因此我们放弃了这个想法,因为拥有视图层固有的额外复杂性。
那么,我们有哪些选择?我们可以想到一些,但都各有利弊:
表结构的非规范化
在用户表和内容表之间添加多个直接外键约束 - 因此每个内容子类型的内容表会有不同的外键。
优点:
- 通过使用其主键加入内容表将更加优化。
缺点:
- 我们现有的存储过程和网站代码会有很多变化。
- 维护多达 8 个额外的外键(更实际地,我们只使用其中的 2 个)不会像当前的单个键那样容易。
表结构的更多非规范化
只需将我们需要的字段从内容表直接复制到用户表中即可。
优点:
- 不再连接内容表 - 这大大减少了 SQL 必须做的工作。
缺点
- 同上:用户表中需要维护的额外字段,SQL 和网站代码的更改。
创建中间层索引层
使用类似 Lucene.NET,我们会在数据库之上放置一个索引层。从理论上讲,这将提高所有搜索的性能,同时减少服务器上的负载。
优点:
- 这是一个很好的长期解决方案。 Lucene 的存在是为了提高搜索引擎的性能。
缺点:
- 短期内会有更大的开发成本 - 我们需要尽快解决这个问题。
所以这些是我们想出的东西,在这个阶段,我们认为第二种选择是最好的 - 我知道非规范化有它的问题,但有时最好牺牲架构纯度以获得性能提升,因此我们准备支付这笔费用。
还有其他方法可能对我们有用吗?我上面概述的方法是否有任何其他优点和/或缺点可能会影响我们的决定?
【问题讨论】:
-
你能发布其中一个慢查询(加上执行计划)吗?
-
另外,SQL Server 版本是多少?
-
我可以告诉您,我们使用的是 SQL Server 2008 - 但是,在与同事讨论后,我们决定实际查询包含的细节过于敏感,我们无法发布。我可以告诉你的是,大部分查询成本是使用 content_sub_type_id 从内容表中进行非聚集索引查找。接下来是针对内容表的 content_group_id 哈希匹配 - 这些占性能影响的 75%。第三个代价高昂的操作是针对用户表的 id 字段的 != 子句。抱歉,我不能比这更具体了。
标签: sql-server sql-server-2008 search database-performance