如何在控制台中的activerecord-sqlserver-adapter中调试sql查询

时间:2017-08-07 14:02:55

标签: ruby-on-rails sql-server activerecord

如果有人有几个免费的小时(或几天)来帮助我优化几个电话,并希望获得报酬(我可以提供每小时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'.:

任何想法如何改进?

1 个答案:

答案 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替换了子查询,并且我在不到一个小时的时间内运行了它。