如果有人有几个免费的小时(或几天)来帮助我优化几个电话,并希望获得报酬(我可以提供每小时150美元)的帮助,我真的很想得到你的帮助。我绝望了:)
我有一些非常慢的SQL查询:
Panel Load (1075.7ms) EXEC sp_executesql N'SELECT [panels].* FROM [panels] WHERE [panels].[agglo_code_id] = @0 AND [panels].[environment_id] = @1 AND [panels].[product_id] = @2 AND (NOT EXISTS(SELECT 1 FROM campaign_search_panels WHERE campaign_search_panels.panel_id = panels.panel_id AND campaign_search_panels.campaign_id = 32)) AND (NOT EXISTS(SELECT 1 FROM "AIDAAU_Avails" WHERE "AIDAAU_Avails"."PanelID" = panels.panel_uid AND "AIDAAU_Avails"."TillDate" >= ''08-21-2017'' AND "AIDAAU_Avails"."FromDate" <= ''09-03-2017''))', N'@0 int, @1 int, @2 int', @0 = 24, @1 = 14, @2 = 25 [["agglo_code_id", 24], ["environment_id", "14"], ["product_id", "25"]]
我正在试图弄清楚如何调试这个但我无法做到这一点。我想对它进行解释但是我不能直接通过sql客户端访问数据库,因为它被锁定到服务器的ip,所以我试图通过rails console来实现服务器。
我可以执行以下操作(不确定为什么会运行两个查询):
irb(main):049:0> ActiveRecord::Base.connection.execute('SELECT [panels].* FROM [panels] WHERE [panels].[agglo_code_id] = 24 AND [panels].[environment_id] = 14 AND [panels].[product_id] = 25 AND (NOT EXISTS(SELECT 1 FROM campaign_search_panels WHERE campaign_search_panels.panel_id = panels.panel_id AND campaign_search_panels.campaign_id = 32)) AND (NOT EXISTS(SELECT 1 FROM "AIDAAU_Avails" WHERE "AIDAAU_Avails"."PanelID" = panels.panel_uid AND "AIDAAU_Avails"."TillDate" >= ''08-21-2017'' AND "AIDAAU_Avails"."FromDate" <= ''09-03-2017''))')
(47.3ms) SELECT [panels].* FROM [panels] WHERE [panels].[agglo_code_id] = 24 AND [panels].[environment_id] = 14 AND [panels].[product_id] = 25 AND (NOT EXISTS(SELECT 1 FROM campaign_search_panels WHERE campaign_search_panels.panel_id = panels.panel_id AND campaign_search_panels.campaign_id = 32)) AND (NOT EXISTS(SELECT 1 FROM "AIDAAU_Avails" WHERE "AIDAAU_Avails"."PanelID" = panels.panel_uid AND "AIDAAU_Avails"."TillDate" >= 08-21-2017 AND "AIDAAU_Avails"."FromDate" <= 09-03-2017))
(47.3ms) SELECT [panels].* FROM [panels] WHERE [panels].[agglo_code_id] = 24 AND [panels].[environment_id] = 14 AND [panels].[product_id] = 25 AND (NOT EXISTS(SELECT 1 FROM campaign_search_panels WHERE campaign_search_panels.panel_id = panels.panel_id AND campaign_search_panels.campaign_id = 32)) AND (NOT EXISTS(SELECT 1 FROM "AIDAAU_Avails" WHERE "AIDAAU_Avails"."PanelID" = panels.panel_uid AND "AIDAAU_Avails"."TillDate" >= 08-21-2017 AND "AIDAAU_Avails"."FromDate" <= 09-03-2017))
=> 1143
它比上面的速度要快得多,但是因为我已经替换了所有的标量变量,为什么它更快?有什么方法可以完全相同地运行查询吗?即:
query = <<-SQL
EXEC sp_executesql N'SELECT [panels].* FROM [panels] WHERE [panels].[agglo_code_id] = @0 AND [panels].[environment_id] = @1 AND [panels].[product_id] = @2 AND (NOT EXISTS(SELECT 1 FROM campaign_search_panels WHERE campaign_search_panels.panel_id = panels.panel_id AND campaign_search_panels.campaign_id = 32)) AND (NOT EXISTS(SELECT 1 FROM "AIDAAU_Avails" WHERE "AIDAAU_Avails"."PanelID" = panels.panel_uid AND "AIDAAU_Avails"."TillDate" >= ''08-21-2017'' AND "AIDAAU_Avails"."FromDate" <= ''09-03-2017''))', N'@0 int, @1 int, @2 int', @0 = 24, @1 = 14, @2 = 25 [["agglo_code_id", 24], ["environment_id", "14"], ["product_id", "25"]]
SQL
ActiveRecord::Base.connection.execute(query)
ActiveRecord::StatementInvalid: TinyTds::Error: Incorrect syntax near '["agglo_code_id", 24'.:
任何想法如何改进?
答案 0 :(得分:0)
如果没有执行计划,诊断确切的性能问题将非常困难。但是,只要看一下你的SQL,我就会看到一个巨大的红旗,这可能是你的性能问题。
SELECT
[panels].*
FROM [panels]
WHERE
[panels].[agglo_code_id] = @0
AND
[panels].[environment_id] = @1
AND
[panels].[product_id] = @2
AND
(
NOT EXISTS( SELECT 1
FROM campaign_search_panels
WHERE
campaign_search_panels.panel_id = panels.panel_id
AND
campaign_search_panels.campaign_id = 32)
)
AND
(
NOT EXISTS( SELECT 1
FROM AIDAAU_Avails
WHERE
AIDAAU_Avails.PanelID = panels.panel_uid
AND
AIDAAU_Avails.TillDate >= '08-21-2017'
AND
AIDAAU_Avails.FromDate <= '09-03-2017')
)
当我提取动态SQL并使其漂亮时,我发现了两个可能导致性能问题的事情。首先,你有一个SELECT *
,它将从表中获取每一列,无论你是否需要它。你可能会放慢速度,因为你正在抓住你真正需要的更多数据。
第二件事是我的巨大红旗,你有两个运行SQL查询的NOT EXISTS
子句。根据三个表之间的数据量,这可能是非常昂贵的操作。对于主查询返回的每条记录,您需要运行每个NOT EXISTS
个查询。这意味着如果主查询返回100行,则必须运行200个额外的查询以满足where子句。
要解决此问题,您应该可以将这些NOT EXISTS
替换为两个LEFT JOIN
。我可以猜测如何做,但没有数据可以使用,我无法确定并且不想给你一些让事情变得更糟的东西。
为了让您了解性能差异,我有一个查询做类似的事情。由于数据的大小,需要36小时才能运行。我用某种JOIN
替换了子查询,并且我在不到一个小时的时间内运行了它。