【问题标题】:Query taking to long tuning advice please请咨询长期调整建议
【发布时间】:2013-09-02 03:00:40
【问题描述】:

我有一组包含调查信息的SQL Server 表,我想运行一个查询,其中每个调查有一行,每个答案有一个列。

结构是这样设置的:

ResponseHeader:
 ID (record for each survey)

Responses:
 ID 
 responseHeaderID
 questionID
 answerItemsID

AnswerItems:
 ID   (This is the value needed in each answer column)
 answerText

以下是我提出的查询:

SELECT  ResponseHeader.id
    ,   ResponseHeader.YOS
    ,   ResponseHeader.rankID
    ,   ResponseHeaderunitID
    ,   ResponseHeader.age
    ,   ResponseHeader.gender
    ,   MAX(CASE WHEN Responses.questionID = 42 THEN AnswerItems.id END)
    ,   MAX(CASE WHEN Responses.questionID = 43 THEN AnswerItems.id END)
    ,   MAX(CASE WHEN Responses.questionID = 44 THEN AnswerItems.id END)
    , --.....there are 79 of these lines in the query, one for each question (Responses.questionID)
        MAX(CASE WHEN Responses.questionID = 48 THEN AnswerItems.id END)
    ,   MAX(CASE WHEN Responses.questionID = 48 THEN AnswerItems.id END)
    ,   MAX(CASE WHEN Responses.questionID = 50 THEN AnswerItems.id END)
    ,   MAX(CASE WHEN Responses.questionID = 49 THEN AnswerItems.id END)
FROM ResponseHeader
LEFT OUTER JOIN Responses ON ResponseHeader.id = Responses.responseHeaderID
LEFT OUTER JOIN AnswerItems ON Responses.answerItemsID = AnswerItems.id
WHERE completed = 1
GROUP BY
        ResponseHeader.id
    ,   YOS
    ,   rankID
    ,   unitID
    ,   age
    ,   gender
ORDER BY ResponseHeader.id;

它确实返回了正确的结果集,但在查询分析器中执行需要 18 秒。它返回 4592 行,有 85 列。不幸的是,它达到了IIS 缓冲区限制,因此被认为在经典 ASP 页面中使用非常耗时。增加缓冲区限制不是该作业的选项。我不确定如何通过其他方式获取此信息。

我正在阅读有关枢轴查询的内容,但不理解它们。有没有办法使用这种方法或任何其他方法更快地获得我的结果?

【问题讨论】:

  • @Mat41 。 . .我会将其重写为 pivot 查询,看看是否能提高性能。
  • 你说的那几行给了我每个答案的专栏。我写了这个查询,所以每个答案都有一行,给了我 320000 行。这是我可以弄清楚如何为每个调查(ResponseHeader.id)实现一行并为每个答案实现一列的唯一方法。 @Gordon 我一直在阅读有关这些枢轴查询的信息,但无法理解它们,您能否提供一些帮助?
  • @Mat41 。 . .您应该编辑查询以包含表别名,以便阅读该问题的人对列的来源有所了解。
  • 不包括模式和不使用限定的列名使得我们这些人更难帮助你。也许您可以编辑您的问题(和查询)以提供一些额外的上下文。
  • @Mat41 你试过devart给出的查询吗??

标签: sql sql-server tsql pivot query-performance


【解决方案1】:

试试这样的 -

DECLARE @Responses TABLE (responseHeaderID INT, questionID INT, answerItemsID INT)
DECLARE @ResponseHeader TABLE (id INT, YOS INT, rankID INT, unitID INT, age INT, gender CHAR(1), completed BIT)

SELECT * 
FROM (
    SELECT DISTINCT 
          rh.id
        , rh.YOS
        , rh.rankID
        , rh.unitID
        , rh.age
        , rh.gender
    FROM @ResponseHeader rh
    WHERE completed = 1
) rh
LEFT JOIN (
    SELECT *
    FROM (
        SELECT 
              r.responseHeaderID
            , r.questionID 
            , r.answerItemsID
        FROM @Responses r
    ) t
    PIVOT 
    (
        MAX(answerItemsID) FOR questionID IN ([42], [43], [44], [48], [50], [49])
    ) p
) t2 ON rh.id = t2.responseHeaderID
ORDER BY rh.id

输出 -

【讨论】:

  • 我需要了解这些,看起来很复杂... QA 告诉我有四个问题。前两个指的是“a”。和'r。在这一行'MAX(a.id) FOR r.questionID IN'中它说'与查询中使用的表名或别名不匹配'。它说 't.responseHeaderID' 无法绑定,并且为 'cte' 多次指定了 'responseHeaderID'
  • 是的,效果非常好,谢谢!哇,我原来的查询花了 18 秒。当我将所有 85 个元素放入 '[42]、[43]、[44]、[48]、[50]、[49]' 部分时,使用您的数据透视查询只需不到 1 秒。我很惊讶。一个问题,为什么 questionID 值必须用 [] 包围?通常,当我说 WHERE IN 时,允许使用以角分隔的字符串。由于我假设的“FOR”,为什么不能在这种情况下使用?
  • IN 构造中包含的数值是旋转后的列名。因此,您不能在不使用括号的情况下通过数字指定列名。您在此处阅读的其他信息:blog.sqlauthority.com/2013/08/28/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-27
  • 1970-01-01
  • 1970-01-01
  • 2012-06-15
  • 1970-01-01
相关资源
最近更新 更多