4

我目前正面临一个性能问题(它可能会导致稍后出现扩展问题)问题。我正在处理的应用程序非常复杂,它在 SQL Server 2005 上运行。我需要加入 6 - 7 个表来获取所需的数据。到目前为止,每个表都包含超过 100,000 行数据。无法更改数据库架构(必须保持原样)。所以我只能尽量优化。我想到了两件事:

  • 尽量不要加入数据库,让应用服务器使用LINQ进行过滤:

    • 优点:将能够通过添加更多应用服务器轻松扩展。
    • 缺点:更努力;我不确定响应能力是否会降低。
  • 应用服务器保持原样并尽可能优化 SQL 查询(更多索引、频繁重建索引等):

    • 优点:最小的努力
    • 缺点:当表记录变大时,问题会再次出现

基本上缓存目前不是我的解决方案(硬件问题,托管问题等),这就是我最初没有提出它的原因。但我确实知道缓存会给我带来什么好处,并且已经使用过很多次了。

4

6 回答 6

6

一般来说,在 DBMS 中进行连接。如果您在应用程序服务器中执行此操作,那么您打赌您可以比编写 DBMS 的人更好地优化连接,并且(进一步)您可以通过足以抵消成本的方式超越他们的最佳努力通过网络传输未连接的数据。

现在,如果您要对两个宽表(假设它们是 T1,宽度为 W1 的 N1 行和宽度为 W2 的 N2 行的 T2)进行交叉乘积而不进行过滤,那么 DBMS 必须创建并通过线路发送 N1 * N2 * (W1 + W2) 字节的数据,而您可以将表格分别作为 N1 * W1 + N2 * W2 字节的数据来提取。如果 N1 = N2 = 1M 且 W1 = W2 = 100,那么这是 200 TB 与 200 MB 的数据传输,有利于在应用服务器中进行交叉产品。但这对 DBMS 来说并不完全公平。大多数查询并不是那么傻——它们加入列并应用条件,DBMS 优化器将竭力(并且自动)努力最小化完成的工作。此外,它只会将相关数据发回给您;它不必发送所有与您的条件不匹配的行。

为了展示另一种情况(有利于 DBMS),请考虑以下情况:T1 有 N1 = 1M 行宽度 W1 = 100,但 T2 有 N2 = 100K 行宽度 W2 = 50。一个整数列,因此,T1 中有 10 行,T2 中的每一行。假设您将所有 T1 和 T2 吸入应用服务器:这需要 N1 * W1 + N2 * W2 = 105 MB 的数据。但是过滤条件将数据限制为 T2 中行的 1/10,对于 T1 中与 T2 中的一行匹配的每一行,实际上只有 2 行匹配过滤条件。现在 DBMS 只传输 N2 * (W1 + W2) / 5 = 3 MB,DBMS 节省了超过 100 MB 的数据传输。现在,如果你设法聪明一点,只下载与 T2 中的值相对应的 N2 * W2 / 10 = 500 KB 数据,您仍然必须让 DBMS 对您想要从 T1 到应用服务器的正确行的值执行 T1 的“半连接”。如果您只需要列的一个子集,则可以节省另一组。DBMS 往往有相当聪明的排序包;你需要在你的应用服务器中有一个好的排序包来以正确的顺序呈现数据。

对于 DBMS 中的连接,它通常应该是一个不折不扣的胜利。如果不是,那是因为您要求服务器做的工作超出了它的处理能力。在这种情况下,您需要查看复制数据库服务器是否有意义,或者添加更多内核、更多网络带宽或更多主内存是否可以完成这项工作。

于 2009-03-11T04:51:41.943 回答
2

一般来说,在谈论规模时,我会考虑以下几点:

  1. 它多久执行一次?对于访问频率较低的查询,您可能会接受一些性能下降。

  2. 增长率/变化率是多少?如果其中一些表中的记录相对静态,您可能需要考虑在外部将内容缓存在 dbm 类型的文件(或任何 Windows 等效文件)中。还有像 memcache 这样的东西可能值得一看。不过,这可能会也可能不会。这是基于在应用程序代码中执行“连接”。

  3. 轮廓。如果你加入索引列(你是,不是吗?),你不一定会随着行数的增长而降级。这在很大程度上取决于是在处理 1:1 还是 1:N 关系,N 的平均大小是多少,数据库服务器上有多少可用内存,计算表统计信息的频率,以及列和索引的类型。如果您正在处理 1:1 关系并且它是唯一的,那么数据库将能够进行简单的散列并进行查找。

确保将获取的列限制为绝对不超过您的需要,尤其是在连接许多表时,因为如果连接两个表所需的只是被索引的列,那么数据库甚至可能根本不考虑该表;可以仅使用索引来执行连接。这减少了争用并提高了需要处理表的实际内容的次优查询的性能,因为在表上拉取的查询更少。

所有关系数据库都有一个工具或功能来查看给定查询的查询执行计划。用它。如果输出对您没有意义,请学习它。这是您了解数据库将如何处理给定查询、将使用哪些索引、在每个执行步骤中将遇到的估计(或实际)行数以及其他有趣内容的主要窗口。

一旦您获得了有关查询优化器对查询实际执行的操作的信息,并且您拥有所有索引/统计信息/列选择,您将更好地了解从那里去哪里。如果你在数据库中尽你所能,你将不得不考虑使用数据缓存并做一些事情,比如使用更具体/更好的 where 子句访问更少的表。

免责声明:我对 SQL Server 没有直接经验,但我在其他 RDBMS(Oracle、MySQL、PostgreSQL 等)和一般架构方面有很多经验。

于 2009-03-11T04:28:31.970 回答
1

您需要检查哪些索引已经到位,它们(和统计信息)是否是最新的,以及新索引是否有利于您的查询工作量。

于 2009-03-11T03:27:09.947 回答
1

通过在“不加入”场景中添加更多服务器,您将获得更多的性能提升,或者尝试优化连接。你是对的 - 当你有更多数据时问题会回来。

最好的解决方案是使用内存缓存。您可以缓存大多数尺寸较小的表-表关系,并且不会一直获取它们。

最佳方案是最小化连接,最小化选择,然后将很少更改的数据缓存到内存中。这将起到推动作用。

正如微软(以及其他数据库制造商)关于联接的建议一样 - 尽可能最佳地使用它们。根据我的经验 - 超过 2-3 个加入复杂选择的人数最多。

于 2009-03-11T04:40:00.910 回答
1

你提到每个表都有“超过 100,000 行”,但你没有提到你选择了多少数据,以及连接有多复杂。对于正确设置和索引的 SQLServer,100K 行并不大。我们有 17 路连接,它们在几毫秒内返回结果,但它的索引很好并且选择了几行。在开始重新设计您的应用程序之前,我会查看 SQLServer 上的分析信息。

于 2009-03-11T05:14:47.257 回答
0

不要忽视在服务器之间传输数据的开销。以太网在负载下会迅速下降(我认为持续传输速率大约是单数据包速率的 30%;即,您的 100Mb/秒链路实际上只能处理 30Mb 的大流量)。一旦你在数据库服务器上饱和了你的链接,添加更多的应用服务器就无关紧要了,因为你将无法更快地获取数据。

加入应用程序服务器也会让您受制于最慢的服务器。我们在客户端站点看到性能下降,发现主应用服务器已经崩溃,客户端的恢复策略是让机器故障转移到运行在其他服务器之一上的虚拟机。一种巧妙的解决方案,但肯定不如性能。当路由器出现故障时,我还看到速度变慢,突然间,所有对等服务器都在三到四跳之外,而不是在同一个子网上。

于 2009-04-17T18:22:14.913 回答