Sql server 解决搜索操作性能的最佳策略-SQL Server 2008
我正在开发一个越来越受欢迎的移动网站,这导致了一些关键数据库表的增长——我们开始看到访问这些表时出现一些性能问题。我们不是数据库专家(在这个阶段也没有钱雇佣任何人),我们正在努力理解是什么导致了性能问题。我们的表没有那么大,所以SQL Server应该能够很好地处理它们,并且我们已经在优化查询方面做了所有我们知道要做的事情。下面是(伪)表结构:Sql server 解决搜索操作性能的最佳策略-SQL Server 2008,sql-server,sql-server-2008,search,database-performance,Sql Server,Sql Server 2008,Search,Database Performance,我正在开发一个越来越受欢迎的移动网站,这导致了一些关键数据库表的增长——我们开始看到访问这些表时出现一些性能问题。我们不是数据库专家(在这个阶段也没有钱雇佣任何人),我们正在努力理解是什么导致了性能问题。我们的表没有那么大,所以SQL Server应该能够很好地处理它们,并且我们已经在优化查询方面做了所有我们知道要做的事情。下面是(伪)表结构: [user] (approx. 40,000 rows, 37 cols): id INT (pk) content_gr
[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)
...
我们预计这些行数将大幅增长(特别是用户、内容组和内容表)。是的,用户表有很多列——我们已经确定了一些可以移动到其他表中的列。我们还对受影响的表应用了一系列索引,这些索引起到了帮助作用
最大的性能问题是我们用来搜索用户的存储过程(包括content\u group\u id字段上的content表的连接)。我们已经尝试使用各种不同的方法修改WHERE
和和子句,我们认为我们已经尽可能好地修改了它们,但仍然太慢
我们尝试的另一件没有帮助的事情是在用户和内容表上放置索引视图。当我们这样做时,没有明显的性能提升,因此我们放弃了这个想法,因为拥有一个视图层会带来额外的复杂性
那么,我们的选择是什么?我们可以想到一些,但都有利弊:
表结构的非规范化
在用户表和内容表之间添加多个直接外键约束-因此,对于每个内容子类型,内容表将有不同的外键
优点:
- 通过使用内容表的主键,加入内容表将更加优化
缺点:
- 我们现有的存储过程和网站代码将有很多变化
- 维护多达8个附加外键(更现实地说,我们将只使用其中的2个)不会像当前的单个键那样容易
表结构的更多非规范化
只需将内容表中需要的字段直接复制到用户表中即可
优点:
- 没有更多的内容表的连接-这大大减少了SQL必须做的工作
缺点
- 同上:用户表中要维护的额外字段、对SQL和网站代码的更改
创建中端索引层
使用类似Lucene.NET的东西,我们在数据库上方放置了一个索引层。理论上,这将提高所有搜索的性能,同时降低服务器上的负载
优点:
- 这是一个很好的长期解决方案。Lucene的存在是为了提高搜索引擎的性能
缺点:
- 短期内将有更大的开发成本,我们需要尽快解决这个问题
因此,这些就是我们已经想到的东西,在这个阶段,我们认为第二种选择是最好的-我知道非规范化有它的问题,但有时最好牺牲架构纯度以获得性能收益,所以我们准备支付这一成本
有没有其他可能对我们有用的方法?我上面概述的方法是否还有其他可能影响我们决策的优点和/或缺点
使用
内容\子\类型\ id。后面是
内容表的内容组id
此说明表明您的查询根据content\u type
中的字段过滤content
表:
select ...
from content c
join content_type ct on c.content_type_id = ct.id
where ct.<field> = <value>;
select ...
from content c
where c.content_type_id = @contentTypeId;
这只有在内容类型id的选择性很高的情况下才有效(许多不同的值,每个值只有几行),我怀疑这是您的情况(您可能只有很少的内容类型,每个都有许多条目)
3) 将内容类型反规范化为内容。你提到了非规范化,但你提出的将内容非规范化为用户的建议对我来说毫无意义。放下content\u-type
表,将content\u-type字段拉入content
表本身,接受所有非规范化问题
4) 在物化视图中预联接。你说你已经试过了,但我怀疑你是否尝试了正确的物化视图。您还需要了解,只有Enterprise Edition自动使用物化视图索引,所有其他版本都需要提示:
解决方案2)、3)和4)大多是学术性的。鉴于内容类型id的选择性非常低,您唯一有机会的解决方案是使其成为内容
聚集索引中的前导键。我没有将分析扩展到content\u Sub\u type
,但是只有8行,我敢打赌它也有同样的问题,这需要将它也推到聚集索引中(可能作为第二个前导键)。你能发布其中一个慢查询(加上执行计划)吗,什么是SQL Server版本?我可以告诉您,我们使用的是SQL Server 2008-但是,在与同事讨论后,我们决定实际查询包含的详细信息过于敏感,无法发布。我可以告诉您的是,查询成本的大部分是使用content\u sub\u type\u id从content表进行的非聚集索引查找。然后是content\u group\u id与content表的哈希匹配-这些占性能损失的75%。第三个昂贵的操作是!=子句,该子句针对用户表的id字段。对不起,我不能说得更具体了。雷姆斯,谢谢你的回复。我有一只蜜蜂
create view vwContentType
with schemabinding
as
select content_type_id, content_id
from dbo.content c
join dbo.content_type_id ct on c.content_type_id = ct.content_type_id;
create unique clustered index cdxContentType on vwContentType (content_type_id, content_id);
select ...
from content c
join vwContentType ct with (noexpand)
on ct.content_id = c.content_id
where ct.content_type_id = @contentTypeId;