0

考虑一个简单的 3 表数据库 i SQL Server 2012。

表 A

AId
Name
Other1
Other2

表 B

BId
Name

表 A_B

BId
AId

简单示例查询:

SELECT TOP(20) A.Aid, A.Name, B.Bid, B.Name 
FROM A 
INNER JOIN A_B ON A.AId = A_B.Aid
INNER JOIN A as AA ON AA.Aid = A_B.Aid
INNER JOIN B ON B.BId = A_B.Bid
WHERE AA.Aid = @aid
AND A.Other1 = @other1

表 A
有几百万行。表 B 有几千行
。表 A_B 的行数是 A
的十倍。Other1 和 Other2 字段可用于过滤查询。使用 Top(20) 的连接查询可以以每秒 100 个或更多请求的速度完成(规格尚不清楚)。查询几乎总是使用不同的参数,因此结果缓存无济于事。

SQL Server 2012 中的哪些功能可以帮助提高上述示例的联接查询性能?

我最初的想法是,既然都是 PK int 连接,我无能为力。但是我不知道分区视图是否有帮助。
我在想这可能只是增加内存。

4

2 回答 2

1

首先要了解(可能不是第一个)是所有当前版本都内置了一个性能模型,该模型取决于磁头寻道时间与连续读取,这可能会随着固态驱动器而改变。您选择的聚集索引对于将可能经常查询的数据保持在一起很重要。此外,查询的每个部分都有一个覆盖索引,这意味着可以在不读取表本身的情况下访问数据。分区可能会有所帮助(但它可能在列表中很长的路要走)。保持最新的统计数据是必不可少的。性能不佳通常来自维护不足的索引和统计信息。实际上,所有这些事情在 SQL7 中都是正确的(除了我认为 SQL7 没有分区视图)。拥有正确的 RAID 结构可以将性能改变 4 倍。tempdb 的数量应等于处理器的数量(最多约 16 个),并且 tempdb 负载平衡选项应设置为 true。将 Tempdbs、日志和数据分布在不同的 i/os 上。没有自动收缩 - 它的邪恶。这些是比较明显的。如果您真的想掌握大型数据库,那么 Kalen Delany 的“Inside SQL”几乎是必读的,尽管可能要花费更多 GB 的 RAM。正如你所说 - 更多的内存。Kalen Delany 的著作几乎是强制性阅读,尽管可能要花费几 GB 的 RAM。正如你所说 - 更多的内存。Kalen Delany 的著作几乎是强制性阅读,尽管可能要花费几 GB 的 RAM。正如你所说 - 更多的内存。

于 2013-06-20T15:23:48.180 回答
1

首先是的 PK 有一个聚集索引

如果表 B 小于 Int16,则使用 Int16
不是用于磁盘空间,而是用于相同内存量中的更多行

有趣的部分是表 A_B
该 PK 的顺序可能会影响性能
仅针对第二个的单个 PK 索引将是一个较慢的连接

尝试每种方式的顺序
检查查询计划
检查调优顾问

我的想法是
PK AId,
BId 基于该索引的 BId 上的非聚集索引更小

然后将它们翻转并比较
如果相同,则使用 AId、BId 以获得更小的索引大小和插入速度

然后你可以进入关于连接的提示

定期进行碎片整理

按PK顺序插入

如果数据以自然顺序出现并且插入速度是一个问题,则使用该顺序进行 PK

如果插入速度有问题,那么禁用非聚集索引,插入,然后重建非聚集索引可能会有所帮助

数以百万计仍然不是巨大的。

而且我不会写这样的查询
保持数字加入

SELECT TOP(20) A.Aid, A.Name, B.Bid, B.Name 
  FROM A_B 
  JOIN A  
    ON A.Aid = A_B.Aid
  JOIN B 
    ON B.BId = A_B.Bid
 WHERE AA.Aid = @aid
   AND A.Other1 = @other1

那个查询很浪费
为什么加入所有 A.Aid = A_B.Aid 来过滤到 where 中的单个 AA.Aid
获取过滤器提前执行

这可能会表现得更好

SELECT TOP(20) A.Aid, A.Name, B.Bid, B.Name 
  FROM A_B 
  JOIN A  
    ON A.Aid = A_B.Aid
   AND A.Aid = @aid 
   AND A.Other1 = @other1
  JOIN B 
    ON B.BId = A_B.Bid

如果您可以在它加入之前对其进行过滤,那么工作量就会减少
检查查询计划

具有条件的 A 上的 CTE 可能会强制它首先执行过滤器。

如果您无法通过单个语句首先发生过滤器,则创建一个带有 ID 的 #tempA 作为声明的 PK
(不是 CTE,目的是实现)

Insert into #tempA 
select Id, Name 
  from Table A 
 where A.Aid = @aid 
   AND A.Other1 = @other1

如果 Id 是表 A 上的 PK,则该查询返回 0 或 1 条记录
连接到 #tempA 是微不足道的

于 2013-06-20T16:21:21.827 回答