此查询有效(感谢那些有帮助的人)生成30天的移动平均值。
SELECT x.symbol, x.dseqkey, AVG(y.VOLUME) moving_average
FROM STOCK_HIST x, STOCK_HIST y
WHERE x.dseqkey>=29 AND x.dseqkey BETWEEN y.dseqkey AND y.dseqkey+29
AND Y.Symbol=X.Symbol
GROUP BY x.symbol, x.dseqkey
ORDER BY x.dseqkey DESC
然而表现非常糟糕。我正在运行上面的视图(STOCK_HIST),它将两个表(A和B)放在一起。表A包含每日库存量和超过9,000种库存的日期,这些库存可追溯到40年前(每年300多行,每9,000种库存)。表B是“日期密钥”表,它将表A中的日期链接到DSEQKEY(int)。
我对绩效改进有哪些选择?我听说观点很方便,但效果不佳。我应该只将表A和B中所需的列复制到单个表中,然后运行上面的查询吗?我在股票代码+日期(A)和DSEQKEY(B)上的表A和B上有索引。
这是否会影响我的表现?我怎样才能改善这个?
修改
根据要求,我已发布了2个表格和下面的视图。此外,现在视图和每个表上都有一个聚簇索引。我对任何建议持开放态度,因为产生deisred结果的查询仍然很慢:
SELECT
x.symbol
, x.dseqkey
, AVG(y.VOLUME) moving_average
FROM STOCK_HIST x
JOIN STOCK_HIST y ON x.dseqkey BETWEEN y.dseqkey AND y.dseqkey+29 AND Y.Symbol=X.Symbol
WHERE x.dseqkey >= 15000
GROUP BY x.symbol, x.dseqkey
ORDER BY x.dseqkey DESC ;
这是观点:
CREATE VIEW [dbo].[STOCK_HIST]
WITH SCHEMABINDING
AS
SELECT
dbo.DATE_MASTER.date
, dbo.DATE_MASTER.year
, dbo.DATE_MASTER.quarter
, dbo.DATE_MASTER.month
, dbo.DATE_MASTER.week
, dbo.DATE_MASTER.wday
, dbo.DATE_MASTER.day
, dbo.DATE_MASTER.nday
, dbo.DATE_MASTER.wkmax
, dbo.DATE_MASTER.momax
, dbo.DATE_MASTER.qtrmax
, dbo.DATE_MASTER.yrmax
, dbo.DATE_MASTER.dseqkey
, dbo.DATE_MASTER.wseqkey
, dbo.DATE_MASTER.mseqkey
, dbo.DATE_MASTER.qseqkey
, dbo.DATE_MASTER.yseqkey
, dbo.DATE_MASTER.tom
, dbo.QP_HISTORY.Symbol
, dbo.QP_HISTORY.[Open] as propen
, dbo.QP_HISTORY.High as prhigh
, dbo.QP_HISTORY.Low as prlow
, dbo.QP_HISTORY.[Close] as prclose
, dbo.QP_HISTORY.Volume
, dbo.QP_HISTORY.QRS
FROM dbo.DATE_MASTER
INNER JOIN dbo.QP_HISTORY ON dbo.DATE_MASTER.date = dbo.QP_HISTORY.QPDate ;
这里是DATE_MASTER表:
CREATE TABLE [dbo].[DATE_MASTER] (
[date] [datetime] NULL
, [year] [int] NULL
, [quarter] [int] NULL
, [month] [int] NULL
, [week] [int] NULL
, [wday] [int] NULL
, [day] [int] NULL
, [nday] nvarchar NULL
, [wkmax] [bit] NOT NULL
, [momax] [bit] NOT NULL
, [qtrmax] [bit] NOT NULL
, [yrmax] [bit] NOT NULL
, [dseqkey] [int] IDENTITY(1,1) NOT NULL
, [wseqkey] [int] NULL
, [mseqkey] [int] NULL
, [qseqkey] [int] NULL
, [yseqkey] [int] NULL
, [tom] [bit] NOT NULL
) ON [PRIMARY] ;
这是QP_HISTORY表:
CREATE TABLE [dbo].[QP_HISTORY] (
[Symbol] varchar NULL
, [QPDate] [date] NULL
, [Open] [real] NULL
, [High] [real] NULL
, [Low] [real] NULL
, [Close] [real] NULL
, [Volume] [bigint] NULL
, [QRS] [smallint] NULL
) ON [PRIMARY] ;
这是观点(STOCK_HIST)指数
CREATE UNIQUE CLUSTERED INDEX [ix_STOCK_HIST] ON [dbo].[STOCK_HIST]
(
[Symbol] ASC,
[dseqkey] ASC,
[Volume] ASC
)
这是QP_HIST指数
CREATE UNIQUE CLUSTERED INDEX [IX_QP_HISTORY] ON [dbo].[QP_HISTORY]
(
[Symbol] ASC,
[QPDate] ASC,
[Close] ASC,
[Volume] ASC
)
这是DATE_MASTER的索引
CREATE UNIQUE CLUSTERED INDEX [IX_DATE_MASTER] ON [dbo].[DATE_MASTER]
(
[date] ASC,
[dseqkey] ASC,
[wseqkey] ASC,
[mseqkey] ASC
)
我没有设置任何主键。这有助于提高绩效吗?
编辑 - 进行建议的更改后,查询速度比以前慢。在10米44秒跑的是目前30米并且仍在运行。
我做了所有请求的更改,除了我没有更改Date_Master中的日期名称,我没有从QP_Hist中删除QPDate列。 (我有理由这样做,并且没有看到它影响性能,因为我在查询中没有提到它。)
修改过的查询
select x.symbol, x.dmdseqkey, avg(y.volume) as moving_average
from dbo.QP_HISTORY as x
join dbo.QP_HISTORY as y on (x.dmdseqkey between y.dmdseqkey and (y.dmdseqkey + 29))
and (y.symbol = x.symbol)
where x.dmdseqkey >= 20000
group by x.symbol, x.dmdseqkey
order by x.dmdseqkey desc ;
PK on QP_History
ALTER TABLE [dbo].[QP_HISTORY]
ADD CONSTRAINT [PK_QP_HISTORY] PRIMARY KEY CLUSTERED ([Symbol] ASC, DMDSeqKey] ASC)
QP_History上的FK
ALTER TABLE [dbo].[QP_HISTORY] ADD CONSTRAINT [FK_QP_HISTORY_DATE_MASTER] FOREIGN KEY([DMDSeqKey]) REFERENCES [dbo].[DATE_MASTER] ([dseqkey])
在Date_Master上的PK
ALTER TABLE [dbo].[DATE_MASTER]
ADD CONSTRAINT [PK_DATE_MASTER] PRIMARY KEY CLUSTERED ([dseqkey] ASC)
编辑
这是执行计划
答案 0 :(得分:4)
首先,单独加入过滤器。
(编辑:修复ON条款)
SELECT x.symbol, x.dseqkey, AVG(y.VOLUME) moving_average
FROM
STOCK_HIST x
JOIN
STOCK_HIST y ON x.dseqkey BETWEEN y.dseqkey AND y.dseqkey+29
AND Y.Symbol=X.Symbol
WHERE x.dseqkey>=29
GROUP BY x.symbol, x.dseqkey
ORDER BY x.dseqkey DESC
另外,你有什么索引 - 我建议索引(dseqkey,symbol)INCLUDE(VOLUME)
编辑3:你不能在聚集索引中拥有INCLUDE,我的不好。你的语法还可以。
请尝试这些排列......目标是找到JOIN和WHERE的最佳索引,然后是ORDER BY。
CREATE UNIQUE CLUSTERED INDEX [ix_STOCK_HIST] ON [dbo].[STOCK_HIST] (...
...[Symbol] ASC, [dseqkey] ASC, [Volume] ASC )
...[dseqkey] ASC, [Symbol] ASC, [Volume] ASC )
...[Symbol] ASC, [dseqkey] DESC, [Volume] ASC )
...[dseqkey] DESC, [Symbol] ASC, [Volume] ASC )
答案 1 :(得分:3)
SQL Server
不支持LAG
和LEAD
中提供的Oracle
或PostgreSQL
条款,也不支持MySQL
等会话变量。
计算移动窗口的聚合是SQL Server
中的一个难点。
所以天知道我不想这样说,但是,在这种情况下,基于CURSOR
的解决方案可能更有效。
答案 2 :(得分:1)
尝试在视图上放置聚集索引。这将使视图像普通表一样持久化到磁盘,并且不必每次都访问您的表。
应该加快速度。
要获得更好的答案,请将链接发布到原始问题,看看是否能找到更好的解决方案。
答案 3 :(得分:0)
有了这个,你可以直接在历史表上运行查询,不需要视图并加入dbo.DATE_MASTER
。
select
x.symbol
, x.dseqkey
, avg(y.volume) as moving_average
from dbo.QP_HISTORY as x
join dbo.QP_HISTORY as y on (x.dSeqKey between y.dSeqKey and (y.dSeqKey + 29))
and (y.symbol = x.symbol)
where x.dseqkey >= 15000
group by x.symbol, x.dseqkey
order by x.dseqkey desc
OPTION (ORDER GROUP) ;
QP_HISTORY
比STOCK_HISTORY
视图更窄,因此查询应该更快。 "冗余列删除"来自联接的计划用于下一代SQL Server(Denali),因此暂时较窄通常意味着更快 - 至少对于大型表来说。此外,join on ..
和where
子句与PK(Symbol, dSeqKey)
很匹配。
现在,如何实现这个目标:
a)将[date]
中的dbo.DATE_MASTER
列修改为类型date
而不是datetime
。将其重命名为FullDate
以避免混淆。不是绝对必要,而是为了保持我的理智。
b)将PK添加到dbo.DATE_MASTER
alter table dbo.DATE_MASTER add constraint primary key pk_datemstr (dSeqKey);
c)在表格QP_HISTORY
中添加列dSeqKey
并填充该列以匹配QPDate
个日期。
d)从表中删除QPDate
列。
e)将PK和FK添加到QP_HISTORY
alter table dbo.QP_HISTORY
add constraint pk_qphist primary key (Symbol, dSeqKey)
, add constraint fk1_qphist foreign key (dSeqKey)
references dbo.DATE_MASTER(dSeqKey) ;
f)至少暂时放弃你问题末尾提到的所有索引。
g)我没有看到Symbol
字段的大小。将其定义为尽可能窄。
h)首先在开发系统上说,实现并测试它。