在哪里做连接 - 在数据库服务器或应用程序服务器中?

时间:2009-03-11 03:20:05

标签: database performance join scaling

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

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

    • 优点:可以通过添加更多应用服务器轻松扩展。
    • 缺点:更多的努力;我不确定是否会降低响应能力。
  • 应用程序服务器保持原样并尝试尽可能优化SQL查询(更多索引,经常重建索引等):

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

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

7 个答案:

答案 0 :(得分:4)

一般来说,在DBMS中加入。如果你在应用程序服务器中这样做,你打赌你可以比编写DBMS的人更好地优化连接,并且(进一步)你可以超出他们的最大努力来抵消成本通过网络传输未加入的数据。

现在,如果你打算做两个宽表的交叉产品(假设它们是T1,N1行的宽度为W1和T2,N2行的宽度为W2)没有过滤,那么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的情况。因此,整数列上有两个表,因此T2中的每一个都有10行。假设您将所有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中的联接,它通常应该是一个不折不扣的胜利。如果不是,那是因为您要求服务器完成的工作量超出其处理能力。在这种情况下,您需要查看复制数据库服务器是否有意义,或者是否添加更多内核,更多网络带宽或更多主内存将完成此任务。

答案 1 :(得分:2)

一般来说,在谈论规模时我会考虑一些观点:

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

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

  3. 资料。如果您正在加入索引列(并且您是,不是吗?),那么随着行数的增加,您不一定会降级。对于你是处理1:1还是1:N关系,N的平均大小,数据库服务器上可用内存的容量,如何处理 通常会计算您的表统计信息,以及列和索引的类型。如果您正在处理1:1关系并且它是唯一的,那么数据库将能够进行简单的哈希并查找。

  4. 确保将提取的列限制为绝对不超过所需的列,尤其是在连接多个表时,因为如果连接两个表所需的全部是索引的列,则数据库可能甚至不考虑该表一点都没只需使用索引即可执行连接。这减少了争用并提高了需要处理表的实际内容的不太理想的查询的性能,因为查询表上的查询较少。

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

    一旦您获得有关查询优化器实际对查询执行的操作的信息,并且您已完成所有索引/统计/列选择,您就可以更好地了解从那里开始的位置。如果你在数据库中尽你所能,你将不得不考虑使用数据的缓存,并采取更少特定/更好的where子句来处理更少的表。

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

答案 2 :(得分:1)

您需要检查已经存在哪些索引,它们(和统计信息)是否是最新的,以及新索引是否会使您的查询工作负载受益。

答案 3 :(得分:1)

通过在“不加入”方案中添加更多服务器,您可以在尝试优化联接时获得更多性能提升。你是对的 - 如果你有更多的数据,问题会回来。

最好的解决方案是使用内存缓存。您可以缓存表 - 表关系,这些关系的大小通常很小,并且不会一直提取它们。

最佳方法是最小化连接,最小化选择,然后将很少更改的数据缓存到内存中。这将有助于推动。

来自Microsoft(以及其他数据库制造商)关于联接的建议 - 尽可能使用它们。根据我的经验 - 复杂选择的顶级数字超过2-3个。

答案 4 :(得分:1)

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

答案 5 :(得分:0)

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

在应用服务器上加入也会让你受到最慢的一方的支配。我们在客户端站点看到了性能槽,发现主应用服务器已经崩溃,客户端的恢复策略是让机器故障转移到在其他服务器上运行的虚拟机。有点整洁的解决方案,但肯定不是高效的。当路由器发生故障时,我也看到减速,突然所有对等服务器都在三跳或四跳之外而不是在同一个子网上。

答案 6 :(得分:-1)

只需添加更多内存。一个完全适合RAM的数据库可以解决很多错误。