改进/重构慢查询的技巧?

Dav*_*ary 5 performance sql-server-2008 t-sql performance-tuning

我们来玩乐透吧!

好的。我有一个numbers80 行(数字 1-80)的表:

create table dbo.numbers (knum tinyint primary key identity);
Run Code Online (Sandbox Code Playgroud)

我有一张桌子,上面有drawid,每个数字都画出来了。

create table dbo.draws (drawid int, drawnumber tinyint);
Run Code Online (Sandbox Code Playgroud)

现在,鉴于该draws表可能包含以下数据:

drawid   drawnumber
  1         10
  1         36
  1         54
  1         75
  2          9
  2         45
  2         46
  2         72
Run Code Online (Sandbox Code Playgroud)

我想知道最后一次出现每种可能的三数排列是什么时候。

我正在使用这个:

declare @curdraw int
select @curdraw = max( drawid)-100 from draws;

select TOP 10 K1,K2,K3, @curdraw-max(d1.drawid)  from THREES 
inner join DrawNumbers d1 WITH (NOLOCK) ON K1 = D1.DRAWNUMBER
INNER JOIN DRAWNUMBERS D2 WITH (NOLOCK) ON K2 = D2.DRAWNUMBER AND D1.DRAWID = D2.DRAWID
INNER JOIN DRAWNUMBERS D3 WITH (NOLOCK) ON K3 = D3.DRAWNUMBER AND D1.DRAWID = D3.DRAWID
WHERE D1.DRAWID < @CURDRAW

GROUP  BY K1, K2, K3
ORDER BY @curdraw-max(d1.drawid) DESC
Run Code Online (Sandbox Code Playgroud)

(哦,表Threes是一个包含 1-80 的所有 492,000+ 三个数字组合的表)

有没有更好的方法来做我在这里想做的事情?这个特定的查询非常慢,我相信具有更好数学/分组技能的人可以做得更好。


对评论的回答 - 澄清:

  • 这是一个基诺游戏。每次开奖都有 80 个号码中的 20 个号码。我只是举了 4 个号码作为例子。

  • 两年累积开奖,每天开奖 254 次,每次开奖 20 个号码……Drawnumber目前有 370 万行。此外,我正在寻找的是“在每一个可能的 3 个数字组合中,您能否给我一个排序列表,列出自其中任何一个命中以来已经过了多长时间,按该长度排序”。

  • top 10仅仅是因为我不需要查看所有 490K 结果。

主键:

USE [OKD] 
GO 

ALTER TABLE [dbo].[DrawNumbers] 
  ADD CONSTRAINT [PK_DrawNumbers] 
  PRIMARY KEY CLUSTERED 
    ( [DrawID] ASC, [DrawNumber] ASC )
  WITH 
   (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
    SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, 
    ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON
    ) ON [PRIMARY]
GO

USE [OKD] 
GO

ALTER TABLE [dbo].[threes] 
  ADD PRIMARY KEY CLUSTERED 
    ( [THREEID] ASC )
  WITH
    (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
     SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, 
     ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON
    ) ON [PRIMARY]
GO
Run Code Online (Sandbox Code Playgroud)

Dav*_*tch -1

将其更改为使用 CTE 可能会更快 - 它们通常会给优化器更好的机会来优化查询。

with currentdraw as (
select k1,k2,k3 from THREES 
inner join DrawNumbers d1 WITH (NOLOCK) ON K1 = D1.DRAWNUMBER
INNER JOIN DRAWNUMBERS D2 WITH (NOLOCK) ON K2 = D2.DRAWNUMBER AND D1.DRAWID = D2.DRAWID
INNER JOIN DRAWNUMBERS D3 WITH (NOLOCK) ON K3 = D3.DRAWNUMBER AND D1.DRAWID = D3.DRAWID
WHERE D1.DRAWID = @CURDRAW
), previousdraws as (
select d1.drawid, k1,k2,k3 from THREES 
inner join DrawNumbers d1 WITH (NOLOCK) ON K1 = D1.DRAWNUMBER
INNER JOIN DRAWNUMBERS D2 WITH (NOLOCK) ON K2 = D2.DRAWNUMBER AND D1.DRAWID = D2.DRAWID
INNER JOIN DRAWNUMBERS D3 WITH (NOLOCK) ON K3 = D3.DRAWNUMBER AND D1.DRAWID = D3.DRAWID
WHERE D1.DRAWID < @CURDRAW
)
select previousdraws.*
from previousdraws p
inner join currentdraw c
on p.k1 = c.k1 and p.k2 = c.k2 and p.k3 = c.k3
order by drawid desc
Run Code Online (Sandbox Code Playgroud)

你最好的索引可能是:

create index ix1 on THREES (k1,k2,k3);
create index ix1 on DrawNumbers (drawid, drawnumber);
Run Code Online (Sandbox Code Playgroud)