如何提高这个慢查询的性能

Posted

技术标签:

【中文标题】如何提高这个慢查询的性能【英文标题】:How can I improve the performance of this slow query 【发布时间】:2014-07-17 05:45:04 【问题描述】:

我有以下查询,大约需要 10 分钟。我需要这个更快。 有什么想法可以调整此查询吗? r_pos_transaction_head 表的记录略低于 500,000 条,r_pos_transaction_detl 的记录略低于 900,000 条。

我在我认为合适的地方创建了索引(您可以在计划中看到这些索引的使用情况)。

truncate table t_retail_history
insert into t_retail_history
select
  h.source_db as legacy_source_db,
  h.company as legacy_company,
  h.store_code as legacy_store_code,
  h.register as legacy_register,
  cast(h.register as char(1)) + '/' + cast(h.transaction_no as varchar(10)) as legacy_transaction_no,
  t_warehouse.store_number as store_number,
  h.transaction_no as reference,
  convert(varchar(10),dbo.datefromdays(h.date),103) as transaction_date,
  convert(varchar(5),dateadd(second,h.time,cast(cast(getdate() as date) as datetime)), 108) as transaction_time,
  d.product_code as legacy_product_code,
  coalesce(d.colour_no,0) as legacy_colour_no,
  coalesce(g_colour_name_replacement.new_colour_name,s.colour_name,'') as legacy_colour_name,
  coalesce(d.size_no,0) as legacy_size_no,
  coalesce(s.size_code,'') as legacy_size_code,
  d.price_inc_tax as legacy_price_inc_tax,
  d.sku_no as legacy_sku_no,
  null as barcode,
  d.quantity as qty,
  d.nett_total as sales_total,
  null as person_code,
  t_warehouse.destination_busdiv_prefix
from
  svi.r_pos_transaction_head h
inner join
  svi.r_pos_transaction_detl d on
  d.company = h.company
  and d.store_code = h.store_code
  and d.register = h.register
  and d.tx_code = h.transaction_no
inner join
  svi.g_skus s on
  s.company = h.company
  and s.product_code = d.product_code
  and (
    s.colour_position = d.colour_no
    or s.colour_position is null and d.colour_no = 0
  )
  and (
    s.size_position = d.size_no
    or s.size_position is null and d.size_no = 0
  )
left outer join
  g_colour_name_replacement on
  g_colour_name_replacement.product_code = d.product_code
  and g_colour_name_replacement.old_colour_name = s.colour_name
left outer join
  t_warehouse on
  t_warehouse.legacy_svi_code = right('000' + cast(h.store_code as nvarchar(5)),3)
where
  d.quantity <> 0
  and d.nett_total <> 0

任何帮助表示赞赏!

【问题讨论】:

您是否尝试在 Databse Engine Tuning Advisor 中对其进行分析? 你能告诉我们SELECT statement 是否也只接受10minutes 吗?因为如果您要插入大约 1 亿行,则很难对其进行优化:p @user1994514- 不,我没有。我以前没用过,我可以看看。是的,SELECT 需要同样的时间,所以我不认为插入本身是这里的问题。 用您需要的其他表中的列替换所有“整个表”连接怎么样?或者甚至可能创建包含此类信息的临时表并将它们加入主查询可能会有所帮助? 您忘记在该查询中包含 r_pos_transaction_head 表。 【参考方案1】:

查询编写正确,按照大家的建议,尝试在joined字段上添加一些索引。

对我来说,查询的不好的部分是:

and (
    s.colour_position = d.colour_no
    or s.colour_position is null and d.colour_no = 0
)
and (
    s.size_position = d.size_no
    or s.size_position is null and d.size_no = 0
)

因为INNER JOIN 语句中的OR condition性能杀手。他们有很多技巧来避免它(比如对每个条件做 2 个左连接,然后在 where 子句中删除发生空的左连接)。

我只是做了一些其他的研究,我发现这个post on *** 可以为你提供一些建议。您应该尝试使用 Union 选项来不重建所有 SELECT 字段部分。

我没有时间为你重写所有查询,请随时通知我。

【讨论】:

谢谢。我有一种感觉,OR 将成为性能杀手。我工作的一个 DBA 说有时候,数据库基本上可以运行两次查询,基本上在结果​​集之间做一个union。但是,我认为我可以通过在这些源表上运行更新并将空值设置为 0,然后在连接中不使用 OR 来解决此问题。我会玩一玩的。不过,我很感谢您花时间提供帮助! 哈哈,我喜欢 ***!我对上面提到的表进行了更新,将 size_position 和 colour_position 中的空值更新为 0.. 查询耗时 28 秒!!非常感谢。【参考方案2】:

您可以使用索引视图来执行更好的连接。 执行更好的索引,因此它可以使用索引搜索而不是索引扫描。 图片百分比总和不是 100% 别人在哪里?

【讨论】:

【参考方案3】:

您似乎没有支持查询所需的索引。你应该看看你是否可以在你加入的列上创建索引。

【讨论】:

你为什么这么说?如果你看到我的计划,它几乎在所有连接上都使用索引。 使用索引可能是索引查找而不是索引扫描。 @Lock 首先,索引扫描可能意味着 SQL Server 找不到更好的索引来支持您的连接。哈希连接也证明了您的查询没有得到索引的良好支持。

以上是关于如何提高这个慢查询的性能的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的解决方案这么慢,如何提高查询的性能?

后端接口如何提高性能?从MySQLESHBASE等技术一起探讨下!

lucene3.0 通过IndexSearcher.doc(i)获取Document 非常慢,如何提高性能?

后端接口如何提高性能?

mysql查询性能问题,加了order by速度慢了

11如何开启慢日志查询?