我有一个非常大的表 Shelve(大约 1 亿),其中包含书籍的 Shelve 信息。
搁置
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 上创建索引
有人可以建议我一些实现此目标的方法吗?
最佳答案
如果您希望每本书都有一个货架值(value),您可以尝试:
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
并且书籍范围不重叠。
我很好奇你的实际应用是什么。没有图书馆(据我所知)拥有数亿册图书。
编辑:
您可以使用 case
语句处理丢失的 ShelveId
:
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;
如果其他假设成立,这可能会解决您的问题。
编辑二:
如果您想要其他属性,请尝试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
表。
关于sql - 2 列的范围查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27580384/