我有非常大的桌子Shelve(大约1亿),它有书架的搁架信息。
搁置
ShevleID RangeStart RangeEnd
----------------------------------------
1 1 100
2 200 500
3 501 1000
每本书都有唯一编号的BookID。假设你有一本BookID 50的书。 然后Book必须保存在Shelve 1中,因为50介于1和100之间。
图书
BookID BookName
---------------------------
1 Book1
2 Book2
.
.
50 Book3
我的查询就像这样 -
SELECT
BookID,
BookName,
ShelveID
FROM
Book B
LEFT JOIN
Shelve S
ON B.BookID
BETWEEN
S.RenageStart
AND
S.RangeEND
此查询超级慢,因为查询一次只能使用RangeStart或RangeEnd中的一列索引。
我已经尝试过这5个选项 -
在StartIP上创建索引
在EndIP上创建索引
在StartIP上创建包含的索引(包括列EndIP)
在EndIP上创建包含的索引(包括列StartIP)
在StartIP上创建索引,EndIP
有人可以建议我采取一些方法来实现这个目标吗?
答案 0 :(得分:2)
如果您想为每本书设置一个搁置值,您可以尝试:
SELECT b.*,
(SELECT TOP 1 s.ShelveId
FROM Shelve S
WHERE b.BookId >= s.RangeStart
ORDER BY s.RangeStart DESC
) as ShelveId
FROM Book B;
这应该有效地使用Shelve(RangeStart, ShelveId)
上的索引。
这假定您需要一个ShelveId
并且图书范围不重叠。
我很好奇你的真实应用是什么。没有图书馆(据我所知)拥有数以亿计的图书。
编辑:
您可以使用ShelveId
声明处理丢失的case
:
SELECT b.*,
(SELECT TOP 1 (case when b.BookId between s.RangeStart and s.RangeEnd then s.ShelveId end)
FROM Shelve S
WHERE b.BookId >= s.RangeStart
ORDER BY s.RangeStart DESC
) as ShelveId
FROM Book B;
如果其他假设属实,这可能会解决您的问题。
编辑II:
如果您需要其他属性,请尝试cross apply
。它应具有类似的性能特征:
SELECT b.*,
s.*
FROM Book B CROSS APPLY
(SELECT TOP 1 (case when b.BookId between s.RangeStart and s.RangeEnd then s.ShelveId end) as RangeStart, . . .
FROM Shelve S
WHERE b.BookId >= s.RangeStart
ORDER BY s.RangeStart DESC
) s
现在,进行一些实验。我想写一下:
SELECT b.*,
s.*
FROM Book B CROSS APPLY
(SELECT TOP 1 s.*
FROM Shelve S
WHERE b.BookId >= s.RangeStart and b.BookId <= s.RangeEnd
ORDER BY s.RangeStart DESC
) s
但是,这可能会混淆优化引擎并阻止使用索引。如果它有效,那很好。如果它不起作用,我建议使用第一个版本,并为每个变量使用case
。或者,使用相关子查询版本并加入主键上的Shelve
表。