SQL Server:多个连接查询优化

时间:2014-01-27 09:35:11

标签: sql-server

我刚开始使用Microsoft SQL Server而且我遇到了一个问题,我认为这是一个SQL优化问题。你能看一下(见下文)并给我你的反馈意见。

我有两个表定义如下:

floatTable (DateAndTime datetime2(7),
            TagIndex smallint,
            Val float)

stringTable (DateAndTime datetime2(7),
            TagIndex smallint,
            Val float)

我用来获得结果的SQL查询是(不要笑):

DECLARE @startDate DATETIME, @endDate DATETIME
SET @startDate = '20130312 9:00:00'
SET @endDate = '20130313 9:00:00'

USE TensionDB

SELECT t1.DateAndTime, t1.Val AS Winch_1,t2.Val AS Winch_2, t3.Val AS Winch_3, t4.Val AS Winch_4, t5.Val AS Winch_5,
t6.Val AS Winch_6, t7.Val AS Winch_7, t8.Val AS Winch_8, t9.Val AS Latitude, t10.Val AS Longitude
FROM 
((SELECT DISTINCT DateAndTime ,Val FROM dbo.FloatTable 
    WHERE (DateAndTime BETWEEN @startDate AND @endDate) AND TagIndex = 0)t1

INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable 
    WHERE ( DateAndTime BETWEEN @startDate AND @endDate) AND TagIndex = 1)t2
    ON t2.DateAndTime = t1.DateAndTime

INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable
    WHERE (DateAndTime BETWEEN @startDate AND @endDate) AND TagIndex = 2)t3
    ON t3.DateAndTime = t1.DateAndTime

INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable 
    WHERE (DateAndTime BETWEEN @startDate AND @endDate) AND TagIndex = 3)t4
    ON t4.DateAndTime = t1.DateAndTime

INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable 
    WHERE (DateAndTime BETWEEN @startDate AND @endDate) AND TagIndex = 4)t5
    ON t5.DateAndTime = t1.DateAndTime

INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable 
    WHERE (DateAndTime BETWEEN @startDate AND @endDate) AND TagIndex = 5)t6
    ON t6.DateAndTime = t1.DateAndTime

INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable 
    WHERE (DateAndTime BETWEEN @startDate AND @endDate) AND TagIndex = 6)t7
    ON t7.DateAndTime = t1.DateAndTime

INNER JOIN (SELECT DISTINCT DateAndTime,Val FROM dbo.FloatTable 
    WHERE (DateAndTime BETWEEN @startDate AND @endDate) AND TagIndex = 7)t8
    ON t8.DateAndTime = t1.DateAndTime

INNER JOIN (SELECT DISTINCT DateAndTime, Val FROM dbo.StringTable 
    WHERE (DateAndTime BETWEEN @startDate AND @endDate) AND TagIndex = 8)t9
    ON t9.DateAndTime = t1.DateAndTime

INNER JOIN (SELECT DISTINCT DateAndTime, Val FROM dbo.StringTable 
    WHERE (DateAndTime BETWEEN @startDate AND @endDate) AND TagIndex = 9)t10
    ON t10.DateAndTime = t1.DateAndTime)

问题:最大的问题是,即使我得到了正确的结果,查询也会因大量数据而变慢。我很确定还有另一种方法来编写查询,但目前我还没有其他任何想法。

你可以给我一个提示吗?感谢您的任何帮助。

提前谢谢


@Kiril和@Patrick,

使用您的提示和想法,我使用数据透视表重新编写了原始查询。 不幸的是,我仍然必须使用INNER JOIN,因为 stringTable 中的值(Val)是字符串,而 floatTable 中的值(Val)是浮点数。说实话,我必须用两个查询执行更多测试,因为我看不到真正的改进(时间明智),使用数据透视表;除了查询的长度。最后一点,我已将查询嵌入到存储过程中。请在下面找到“最终”代码:

-- ================================================
-- Template generated from Template Explorer using:
-- Create Procedure (New Menu).SQL
--
-- Use the Specify Values for Template Parameters 
-- command (Ctrl-Shift-M) to fill in the parameter 
-- values below.
--
-- This block of comments will not be included in
-- the definition of the procedure.
-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:  xxxx
-- Create date: xxxx
-- Description: retrieves tension data
-- =============================================
CREATE PROCEDURE getTension 
    -- Add the parameters for the stored procedure here
    @startDate datetime = NULL, 
    @endDate datetime = NULL
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for procedure here
    SELECT distinct pvt.DateAndTime
        , pvt.[0] AS Winch_1
        , pvt.[1] AS Winch_2
        , pvt.[2] AS Winch_3
        , pvt.[3] AS Winch_4
        , pvt.[4] AS Winch_5
        , pvt.[5] AS Winch_6
        , pvt.[6] AS Winch_7
        , pvt.[7] AS Winch_8
        , st.Val AS Longitude
        , st1.Val AS Latitude
    FROM FloatTable
        PIVOT
            (MAX(Val)
                FOR TagIndex in ([0],[1],[2],[3],[4],[5],[6],[7])
            ) as pvt
        inner join StringTable st on st.DateAndTime = pvt.DateAndTime and  st.TagIndex = 8
        inner join StringTable st1 on st1.DateAndTime = pvt.DateAndTime and st1.TagIndex = 9
    Where (pvt.DateAndTime between @startDate and @endDate)
    ORDER BY DateAndTime

END
GO

再次感谢您的指导

2 个答案:

答案 0 :(得分:0)

开始将DateAndTimeTagIndex放入索引中。这会产生影响。

另一方面,如果您不需要重复的内连接,您的查询可能会快得多。

您可以用distinct替换group by并使用minmax吗?

另一个选择是使用数据透视表。

像这样:

select *
from   FloatTable
pivot (min(DateAndTime) x, min(Val) y in ([1],[2],[3], ...))

答案 1 :(得分:0)

我认为使用数据透视表会更有效率:

DECLARE @startDate DATETIME, @endDate DATETIME
SET @startDate = '20130312 9:00:00'
SET @endDate = '20130313 9:00:00'


SELECT st.DateAndTime
      , pvt.0 AS Winch_1
      , pvt.1 AS Winch_2
      , pvt.2 AS Winch_3
      , pvt.3 AS Winch_4
      , pvt.4 AS Winch_5
      , pvt.5 AS Winch_6
      , pvt.6 AS Winch_7
      , pvt.7 AS Winch_8
      , pvt.8 AS Latitude
      , pvt.9 AS Longitude
FROM StringTable st
INNER JOIN FloatTable ft on st.DateandTime=ft.DateandTime
pivot 
 ( MAX(Val) for [TagIndex] in ([0], [1], [2], [3], [4], [5], [6], [7], [8], [9])
 order by [st.DateAndTime]
 )pvt

我没有对它进行过测试,所以你可能需要对它进行一些调整,以使其正常工作。