【问题标题】:Slow but simple Query, how to make it quicker?慢而简单的查询,如何让它更快?
【发布时间】:2010-10-24 10:21:01
【问题描述】:

我有一个 6GB 大小的数据库,其中包含大量表,但是较小的查询似乎问题最多,并且想知道可以做些什么来优化它们,例如有一个 Stock、Items 和 Order 表.
Stock 表是库存商品,其中包含大约 100,000 条记录,其中 25 个字段存储 ProductCode、Price 和其他库存特定数据。
Items 表存储有关项目的信息,其中有超过 2,000,000 个,其中超过 50 个字段存储项目名称和有关项目或产品的其他详细信息。
Orders 表存储库存商品的订单,即下订单的时间加上售价,并且有大约 50,000 条记录。

这是来自该数据库的查询:

SELECT Stock.SKU, Items.Name, Stock.ProductCode FROM Stock
INNER JOIN Order ON Order.OrderID = Stock.OrderID
INNER JOIN Items ON Stock.ProductCode = Items.ProductCode
WHERE (Stock.Status = 1 OR Stock.Status = 2) AND Order.Customer = 12345
ORDER BY Order.OrderDate DESC;

鉴于此处的信息可以采取哪些措施来改进此查询,还有其他类似的方法,还有哪些替代方法。但是,无法进一步详细说明数据和数据库的性质,因此如果给出一般的优化技巧和方法,这些将很好,或者任何通常适用于数据库的东西。
数据库是 Windows Server 2003 上的 MS SQL 2000,每个数据库都有最新的服务包。 数据库升级/操作系统升级目前不是选项。


编辑

上述表格中的索引为 Stock.SKU、Items.ProductCode 和 Orders.OrderID。
对于这样的查询,执行计划是 13-16 秒,75% 的时间花在 Stock


感谢到目前为止的所有回复 - 索引似乎是问题所在,给出的所有不同示例都有帮助 - 尽管查询存在一些错误,但这对我有很大帮助,其中一些查询运行得更快,但是结合索引建议,我认为我现在可能走在正确的道路上 - 感谢您的快速回复 - 真的帮助了我,让我考虑到我以前没有想过或不知道的事情!


索引是我的问题,在带有订单(客户)的外键中添加了一个,这 通过将执行时间减半来提高性能!
看起来我有狭隘的视野并专注于查询 - 我已经与 DB 合作了几年,但这非常有帮助。但是感谢所有查询示例,它们是我没有考虑过的组合和功能也可能有用!

【问题讨论】:

  • 您需要发布一些执行计划的详细信息,以便人们知道从哪里开始。无论如何,一个典型的查询需要多长时间?
  • 查询需要 13-16 秒才能运行我有类似的查询,它们主要使用这些表,主要是 Items 和 Stock,执行时间相似 - 大部分都花在 Stock 上,
  • 然后明确地向 Stock.Status 和 Order.Customer 添加索引!

标签: sql sql-server database optimization


【解决方案1】:

你的代码正确吗???我确定你错过了什么

INNER JOIN Batch ON Order.OrderID = Orders.OrderID

你在代码中有一个 ) ...


您始终可以针对执行计划工具测试一些变体,例如

SELECT 
    s.SKU, i.Name, s.ProductCode 
FROM 
    Stock s, Orders o, Batch b, Items i
WHERE 
    b.OrderID = o.OrderID AND
    s.ProductCode = i.ProductCode AND
    s.Status IN (1, 2) AND 
    o.Customer = 12345
ORDER BY 
    o.OrderDate DESC;

并且您应该只返回一个分数,例如 TOP 10...选择 TOP 10 需要几毫秒,但将其绑定到您的应用程序时会节省大量时间。

【讨论】:

  • 也看到了,不过之前发过我的答案。
  • 感谢错过了一个括号 - 实际代码中不存在剪切和加速错误,但无论如何感谢您指出!
  • 不仅如此,您所说的 Order.OrderID 必须等于 INNER JOIN 中的相同 Order.OrderID...
【解决方案2】:

最重要的(如果尚未完成):为表定义主键(如果尚未定义)并为外键和连接中使用的列添加索引。

【讨论】:

  • 感谢您首先提出索引问题 - 这对性能产生了最大的影响,但是提到的所有查询也有帮助!
【解决方案3】:

您是否指定了索引?开

  • Items.ProductCode
  • Stock.ProductCode
  • Orders.OrderID
  • Orders.Customer

有时,IN 可能比 OR 更快,但这不如拥有索引重要。

查看 balexandre 的答案,您的查询看起来不对。

【讨论】:

  • 我有索引,但每个表上只有主键,因为每个表都有唯一的 ID(SKU、产品代码和订单 ID)
  • 这是你的问题——你的外键也需要索引。键是否唯一与索引的要求无关(显然,这不会是唯一索引)。
【解决方案4】:

一些通用指针

  • 您要加入的所有字段是否都已编入索引?

  • ORDER BY 有必要吗?

  • 执行计划是什么样的?

顺便说一句,您似乎没有在问题查询示例中引用 Order 表。

【讨论】:

  • 抱歉,查询中有几个错误,但所有建议都很有帮助,尽管我可以尝试和使用的东西更少,尽管在转录查询时出现错误 - 回复很有帮助,谢谢!
【解决方案5】:

按照 Cătălin Pitiş 的建议,表格索引肯定会有所帮助。

另一个技巧是通过使用 sub select 或更极端地使用临时表来减小连接行的大小。例如,不要加入整个 Orders 表,而是加入

(SELECT * FROM Orders WHERE Customer = 12345)

另外,不要直接加入 Stock 表加入

(SELECT * FROM Stock WHERE Status = 1 OR Status = 2)

【讨论】:

  • 不过,数据库服务器应该足够聪明,可以自行执行这种优化(将过滤谓词推到尽可能低的位置)。
  • 相信我不会。在我的一个项目中,我所做的正是 RoguePlanetoid,查询看起来更优雅,但运行几乎需要一分钟。在我开始使用子选择和临时表后,它现在下降到 5 秒。
【解决方案6】:

在表上设置正确的索引通常是最大的性能差异。

在 Management Studio(或早期版本的查询分析器)中,您可以选择在运行时查看查询的执行计划。在执行计划中,您可以看到数据库真正为获得结果所做的工作,以及哪些部分需要最多的工作。那里有一些东西需要查找,例如表扫描,这通常是查询中成本最高的部分。

表的主键通常有一个索引,但您应该验证它是否确实如此。然后,您可能需要对用于查找记录的字段和用于排序的字段建立索引。

添加索引后,您可以重新运行查询并在执行计划中查看它是否实际使用索引。 (在为数据库创建索引后,您可能需要等待一段时间才能构建索引才能使用它。)

【讨论】:

  • 感谢您的建议 - 从未考虑过主键可能没有与之关联的索引 - 在这种情况下,他们有,但这可能是我不知道的问题!
【解决方案7】:

你可以试一试吗?

SELECT Stock.SKU, Items.Name, Stock.ProductCode FROM Stock
INNER JOIN Order ON Order.OrderID = Stock.OrderID AND (Order.Customer = 12345) AND (Stock.Status = 1 OR Stock.Status = 2))
INNER JOIN Items ON Stock.ProductCode = Items.ProductCode
ORDER BY Order.OrderDate DESC;

【讨论】:

  • 有趣,这似乎以相同的方式执行 - 但是人们给出的所有示例都表明我以前没有尝试过的东西会将这些想法应用于我的其他查询。我认为索引是问题,因为这似乎会导致最慢,尤其是我的 Stock 表。
【解决方案8】:

详细说明 Cătălin Pitiş 已经说过的话:在您的查询中

SELECT Stock.SKU, Items.Name, Stock.ProductCode
    FROM Stock
      INNER JOIN Order ON Order.OrderID = Stock.OrderID
      INNER JOIN Items ON Stock.ProductCode = Items.ProductCode
  WHERE (Stock.Status = 1 OR Stock.Status = 2) AND Order.Customer = 12345
  ORDER BY Order.OrderDate DESC;

标准 Order.Customer = 12345 看起来非常具体,而 (Stock.Status = 1 OR Stock.Status = 2) 听起来不具体。如果这是正确的,一个有效的查询包括

1) 首先找到属于特定客户的订单,

2)然后找到对应的Stock行(具有相同的OrderID)过滤掉那些在(1, 2)中具有Status的行,

3) 最终找到 ProductCode 与 2) 中的 Stock 行相同的商品

对于 1) 您需要对表 Order 的 Customer 的索引,对于 2) 对于表 Stock 的 OrderID 的索引和对于 3) 对于表 Items 的 ProductCode 的索引。

只要您的查询没有变得更加复杂(例如成为更大查询中的子查询,或者 Stock、Order 和 Items 只是视图,而不是表),查询优化器就应该能够从您的查询。否则,您将不得不按照 kuoson 的建议进行操作(但如果 (1, 2) 中的状态不是很具体和/或状态未在状态表中编入索引,则第二个建议无济于事)。但也请记住,如果您对表执行多次插入/更新,则保持索引最新会降低性能。

【讨论】:

    【解决方案9】:

    为了缩短我 2 小时前给出的答案(当我的 cookie 关闭时):

    您需要 三个 索引:表 Order 的 Customer、Stock 的 OrderID 和 Items 的 ProductCode。

    如果您错过了其中任何一个,则必须等待对相应表进行完整的表扫描。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-27
      • 1970-01-01
      • 1970-01-01
      • 2017-08-23
      • 1970-01-01
      • 2019-05-13
      • 1970-01-01
      • 2023-02-16
      相关资源
      最近更新 更多