在没有聚合的情况下旋转多个列 - 性能优化

时间:2018-06-04 09:41:56

标签: sql-server

我对以下查询的性能有疑问,是否可以更有效地转动多个相关列。

SELECT
  TimetableID,
  [Order],
  [Time],
  [Text],
  [1] AS FileID1, Files1.[Filename] AS [File filename1], Files1.[Extension] AS [File extension1], Files1.[Type] AS [File type1], Files1.[Content] AS [File content1],
  [2] AS FileID2, Files2.[Filename] AS [File filename2], Files2.[Extension] AS [File extension2], Files2.[Type] AS [File type2], Files2.[Content] AS [File content2],
  [3] AS FileID3, Files3.[Filename] AS [File filename3], Files3.[Extension] AS [File extension3], Files3.[Type] AS [File type3], Files3.[Content] AS [File content3],
  [4] AS FileID4, Files4.[Filename] AS [File filename4], Files4.[Extension] AS [File extension4], Files4.[Type] AS [File type4], Files4.[Content] AS [File content4],
  [5] AS FileID5, Files5.[Filename] AS [File filename5], Files5.[Extension] AS [File extension5], Files5.[Type] AS [File type5], Files5.[Content] AS [File content5],
  [6] AS FileID6, Files6.[Filename] AS [File filename6], Files6.[Extension] AS [File extension6], Files6.[Type] AS [File type6], Files6.[Content] AS [File content6],
  [7] AS FileID7, Files7.[Filename] AS [File filename7], Files7.[Extension] AS [File extension7], Files7.[Type] AS [File type7], Files7.[Content] AS [File content7],
  [8] AS FileID8, Files8.[Filename] AS [File filename8], Files8.[Extension] AS [File extension8], Files8.[Type] AS [File type8], Files8.[Content] AS [File content8],
  [9] AS FileID9, Files9.[Filename] AS [File filename9], Files9.[Extension] AS [File extension9], Files9.[Type] AS [File type9], Files9.[Content] AS [File content9],
  [10] AS FileID10, Files10.[Filename] AS [File filename10], Files10.[Extension] AS [File extension10], Files10.[Type] AS [File type10], Files10.[Content] AS [File content10],
  [11] AS FileID11, Files11.[Filename] AS [File filename11], Files11.[Extension] AS [File extension11], Files11.[Type] AS [File type11], Files11.[Content] AS [File content11],
  [12] AS FileID12, Files12.[Filename] AS [File filename12], Files12.[Extension] AS [File extension12], Files12.[Type] AS [File type12], Files12.[Content] AS [File content12],
  [13] AS FileID13, Files13.[Filename] AS [File filename13], Files13.[Extension] AS [File extension13], Files13.[Type] AS [File type13], Files13.[Content] AS [File content13],
  [14] AS FileID14, Files14.[Filename] AS [File filename14], Files14.[Extension] AS [File extension14], Files14.[Type] AS [File type14], Files14.[Content] AS [File content14],
  [15] AS FileID15, Files15.[Filename] AS [File filename15], Files15.[Extension] AS [File extension15], Files15.[Type] AS [File type15], Files15.[Content] AS [File content15],
  [16] AS FileID16, Files16.[Filename] AS [File filename16], Files16.[Extension] AS [File extension16], Files16.[Type] AS [File type16], Files16.[Content] AS [File content16],
  [17] AS FileID17, Files17.[Filename] AS [File filename17], Files17.[Extension] AS [File extension17], Files17.[Type] AS [File type17], Files17.[Content] AS [File content17],
  [18] AS FileID18, Files18.[Filename] AS [File filename18], Files18.[Extension] AS [File extension18], Files18.[Type] AS [File type18], Files18.[Content] AS [File content18],
  [19] AS FileID19, Files19.[Filename] AS [File filename19], Files19.[Extension] AS [File extension19], Files19.[Type] AS [File type19], Files19.[Content] AS [File content19],
  [20] AS FileID20, Files20.[Filename] AS [File filename20], Files20.[Extension] AS [File extension20], Files20.[Type] AS [File type20], Files20.[Content] AS [File content20]
FROM
(
  SELECT
    t.[TimetableID],
    t.[Order],
    t.[Time],
    t.[Text],
    tf.N,
    tf.FileID
  FROM
    dbo.Timetables AS t
  LEFT JOIN
    dbo.Timetable_Files AS tf
  ON
    tf.TimetableID = t.TimetableID
) AS [source]
PIVOT
(
  MAX(FileID) FOR N IN ([1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], [15], [16], [17], [18], [19], [20])
) AS [fid]
LEFT JOIN dbo.Files AS Files1 ON Files1.FileID = fid.[1]
LEFT JOIN dbo.Files AS Files2 ON Files2.FileID = fid.[2]
LEFT JOIN dbo.Files AS Files3 ON Files3.FileID = fid.[3]
LEFT JOIN dbo.Files AS Files4 ON Files4.FileID = fid.[4]
LEFT JOIN dbo.Files AS Files5 ON Files5.FileID = fid.[5]
LEFT JOIN dbo.Files AS Files6 ON Files6.FileID = fid.[6]
LEFT JOIN dbo.Files AS Files7 ON Files7.FileID = fid.[7]
LEFT JOIN dbo.Files AS Files8 ON Files8.FileID = fid.[8]
LEFT JOIN dbo.Files AS Files9 ON Files9.FileID = fid.[9]
LEFT JOIN dbo.Files AS Files10 ON Files10.FileID = fid.[10]
LEFT JOIN dbo.Files AS Files11 ON Files11.FileID = fid.[11]
LEFT JOIN dbo.Files AS Files12 ON Files12.FileID = fid.[12]
LEFT JOIN dbo.Files AS Files13 ON Files13.FileID = fid.[13]
LEFT JOIN dbo.Files AS Files14 ON Files14.FileID = fid.[14]
LEFT JOIN dbo.Files AS Files15 ON Files15.FileID = fid.[15]
LEFT JOIN dbo.Files AS Files16 ON Files16.FileID = fid.[16]
LEFT JOIN dbo.Files AS Files17 ON Files17.FileID = fid.[17]
LEFT JOIN dbo.Files AS Files18 ON Files18.FileID = fid.[18]
LEFT JOIN dbo.Files AS Files19 ON Files19.FileID = fid.[19]
LEFT JOIN dbo.Files AS Files20 ON Files20.FileID = fid.[20]

我有以下表结构:

数据库图
  enter image description here

T_Timetable中的每个条目都可以附加多个文件。这是通过T_Timetable_File表实现的。

分配给TimetableID的FileID
  FileIDs assigned to TimetableIDs

我创建了一个视图,为分配表中的每个条目分配一个递增的行号。时间表中每个条目最多有20个文件。

CREATE VIEW
  dbo.Timetable_Files
AS
  SELECT
    TimetableID,
    FileID,
    ROW_NUMBER() over(PARTITION BY TimetableID ORDER BY FileID ASC) AS N
  FROM
    dbo.T_Timetable_File

我需要以下面的格式输出结果,问题顶部的查询已经完成。

结果
  enter image description here

此查询的问题是SQL Server分配给它的内存量。虽然当所有时间表条目包含最多20个文件时,查询可能会返回大量数据,但大多数情况下,条目没有连接到最多5个文件。因此,它也会引发“过度记忆补助”警告。

我对加入“文件”视图的解决方案(视图只是用于以后权限管理的表的所有列的选择)也不太满意20次,以获取20个可能的附加文件的所有文件信息。

CREATE VIEW
  dbo.Files
AS
  SELECT
    ID AS FileID,
    [Filename],
    Extension,
    [Type],
    Content
  FROM
    dbo.T_File

我的问题:是否有更好/更快,更优雅的方式来转动每个文件条目的5列?

编辑:与此同时,我在这里找到了一些东西:

Using pivot and unpivot to pivot multiple columns

使用此信息,我将查询重写为如下所示:

WITH CTE AS
(
  SELECT
    t.[TimetableID],
    t.[Order],
    t.[Time],
    t.[Text],
    N,
    CONVERT(varbinary(MAX), f.FileID) AS FileID, /* f.Content is varbinary, so to unpivot the other columns they have to converted to varbinary, too */
    CONVERT(varbinary(MAX), f.[Filename]) AS [Filename],
    CONVERT(varbinary(MAX), f.Extension) AS Extension,
    CONVERT(varbinary(MAX), f.[Type]) AS [Type],
    f.Content
  FROM
    dbo.Timetables AS t
  LEFT JOIN
    dbo.Timetable_Files AS tf
  ON
    tf.TimetableID = t.TimetableID
  LEFT JOIN
    dbo.Files AS f
  ON
    f.FileID = tf.FileID
)
SELECT
  TimetableID,
  [Order],
  [Time],
  [Text],
  CONVERT(int, FileID1) AS FileID1, CONVERT(varchar(400), Filename1) AS Filename1, CONVERT(varchar(400), Extension1) AS Extension1, CONVERT(varchar(400), Type1) AS Type1, Content1, /*Convert the other columns back to their original type*/
  CONVERT(int, FileID2) AS FileID2, CONVERT(varchar(400), Filename2) AS Filename2, CONVERT(varchar(400), Extension2) AS Extension2, CONVERT(varchar(400), Type2) AS Type2, Content2,
  CONVERT(int, FileID3) AS FileID3, CONVERT(varchar(400), Filename3) AS Filename3, CONVERT(varchar(400), Extension3) AS Extension3, CONVERT(varchar(400), Type3) AS Type3, Content3,
  CONVERT(int, FileID4) AS FileID4, CONVERT(varchar(400), Filename4) AS Filename4, CONVERT(varchar(400), Extension4) AS Extension4, CONVERT(varchar(400), Type4) AS Type4, Content4,
  CONVERT(int, FileID5) AS FileID5, CONVERT(varchar(400), Filename5) AS Filename5, CONVERT(varchar(400), Extension5) AS Extension5, CONVERT(varchar(400), Type5) AS Type5, Content5,
  CONVERT(int, FileID6) AS FileID6, CONVERT(varchar(400), Filename6) AS Filename6, CONVERT(varchar(400), Extension6) AS Extension6, CONVERT(varchar(400), Type6) AS Type6, Content6,
  CONVERT(int, FileID7) AS FileID7, CONVERT(varchar(400), Filename7) AS Filename7, CONVERT(varchar(400), Extension7) AS Extension7, CONVERT(varchar(400), Type7) AS Type7, Content7,
  CONVERT(int, FileID8) AS FileID8, CONVERT(varchar(400), Filename8) AS Filename8, CONVERT(varchar(400), Extension8) AS Extension8, CONVERT(varchar(400), Type8) AS Type8, Content8,
  CONVERT(int, FileID9) AS FileID9, CONVERT(varchar(400), Filename9) AS Filename9, CONVERT(varchar(400), Extension9) AS Extension9, CONVERT(varchar(400), Type9) AS Type9, Content9,
  CONVERT(int, FileID10) AS FileID10, CONVERT(varchar(400), Filename10) AS Filename10, CONVERT(varchar(400), Extension10) AS Extension10, CONVERT(varchar(400), Type10) AS Type10, Content10,
  CONVERT(int, FileID11) AS FileID11, CONVERT(varchar(400), Filename11) AS Filename11, CONVERT(varchar(400), Extension11) AS Extension11, CONVERT(varchar(400), Type11) AS Type11, Content11,
  CONVERT(int, FileID12) AS FileID12, CONVERT(varchar(400), Filename12) AS Filename12, CONVERT(varchar(400), Extension12) AS Extension12, CONVERT(varchar(400), Type12) AS Type12, Content12,
  CONVERT(int, FileID13) AS FileID13, CONVERT(varchar(400), Filename13) AS Filename13, CONVERT(varchar(400), Extension13) AS Extension13, CONVERT(varchar(400), Type13) AS Type13, Content13,
  CONVERT(int, FileID14) AS FileID14, CONVERT(varchar(400), Filename14) AS Filename14, CONVERT(varchar(400), Extension14) AS Extension14, CONVERT(varchar(400), Type14) AS Type14, Content14,
  CONVERT(int, FileID15) AS FileID15, CONVERT(varchar(400), Filename15) AS Filename15, CONVERT(varchar(400), Extension15) AS Extension15, CONVERT(varchar(400), Type15) AS Type15, Content15,
  CONVERT(int, FileID16) AS FileID16, CONVERT(varchar(400), Filename16) AS Filename16, CONVERT(varchar(400), Extension16) AS Extension16, CONVERT(varchar(400), Type16) AS Type16, Content16,
  CONVERT(int, FileID17) AS FileID17, CONVERT(varchar(400), Filename17) AS Filename17, CONVERT(varchar(400), Extension17) AS Extension17, CONVERT(varchar(400), Type17) AS Type17, Content17,
  CONVERT(int, FileID18) AS FileID18, CONVERT(varchar(400), Filename18) AS Filename18, CONVERT(varchar(400), Extension18) AS Extension18, CONVERT(varchar(400), Type18) AS Type18, Content18,
  CONVERT(int, FileID19) AS FileID19, CONVERT(varchar(400), Filename19) AS Filename19, CONVERT(varchar(400), Extension19) AS Extension19, CONVERT(varchar(400), Type19) AS Type19, Content19,
  CONVERT(int, FileID20) AS FileID20, CONVERT(varchar(400), Filename20) AS Filename20, CONVERT(varchar(400), Extension20) AS Extension20, CONVERT(varchar(400), Type20) AS Type20, Content20
FROM
(
  SELECT
    TimetableID,
    [Order],
    [Time],
    [Text],
    Variable + CONVERT(varchar(2), ISNULL(N, '0')) AS [Variable], /* Without the ISNULL timetable entries without files will not be displayed */
    [Value]
  FROM
  (
    SELECT 
      TimetableID,
      [Order],
      [Time],
      [Text],
      N,
      ISNULL(FileID, 0x0) AS FileID,
      [Filename],
      Extension,
      [Type],
      [Content]
    FROM
      CTE
    GROUP BY
      TimetableID,
      [Order],
      [Time],
      [Text],
      N,
      FileID,
      [Filename],
      Extension,
      [Type],
      [Content]
  ) AS origresult
  UNPIVOT
  (
    [Value] FOR Variable IN (FileID, [Filename], Extension, [Type], [Content])
  ) AS unpiv
) AS intermediateresult
PIVOT
(
  MAX([Value]) FOR Variable IN
  (
    FileID1, Filename1, Extension1, Type1, Content1,
    FileID2, Filename2, Extension2, Type2, Content2,
    FileID3, Filename3, Extension3, Type3, Content3,
    FileID4, Filename4, Extension4, Type4, Content4,
    FileID5, Filename5, Extension5, Type5, Content5,
    FileID6, Filename6, Extension6, Type6, Content6,
    FileID7, Filename7, Extension7, Type7, Content7,
    FileID8, Filename8, Extension8, Type8, Content8,
    FileID9, Filename9, Extension9, Type9, Content9,
    FileID10, Filename10, Extension10, Type10, Content10,
    FileID11, Filename11, Extension11, Type11, Content11,
    FileID12, Filename12, Extension12, Type12, Content12,
    FileID13, Filename13, Extension13, Type13, Content13,
    FileID14, Filename14, Extension14, Type14, Content14,
    FileID15, Filename15, Extension15, Type15, Content15,
    FileID16, Filename16, Extension16, Type16, Content16,
    FileID17, Filename17, Extension17, Type17, Content17,
    FileID18, Filename18, Extension18, Type18, Content18,
    FileID19, Filename19, Extension19, Type19, Content19,
    FileID20, Filename20, Extension20, Type20, Content20
  )
) AS piv 

首先使用unpivot为我做了诀窍。该查询不会生成内存警告并且执行速度更快,因为它只访问File表一次(根据SQL Server统计信息)。

我还将尝试larnu建议的方法并比较执行的速度。谢谢到目前为止。

0 个答案:

没有答案