我刚开始使用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
再次感谢您的指导
答案 0 :(得分:0)
开始将DateAndTime
和TagIndex
放入索引中。这会产生影响。
另一方面,如果您不需要重复的内连接,您的查询可能会快得多。
您可以用distinct
替换group by
并使用min
或max
吗?
另一个选择是使用数据透视表。
像这样:
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
我没有对它进行过测试,所以你可能需要对它进行一些调整,以使其正常工作。