Sql 2列上的范围查询
我有一个非常大的书架,大约有1亿个,上面有书架信息 搁置Sql 2列上的范围查询,sql,sql-server,database,query-optimization,Sql,Sql Server,Database,Query Optimization,我有一个非常大的书架,大约有1亿个,上面有书架信息 搁置 ShevleID RangeStart RangeEnd ---------------------------------------- 1 1 100 2 200 500 3 501 1000 每本书都有唯一的BookID号。假设你有一本书号为50的书。 然后
ShevleID RangeStart RangeEnd
----------------------------------------
1 1 100
2 200 500
3 501 1000
每本书都有唯一的BookID号。假设你有一本书号为50的书。
然后书必须放在书架1上,因为50在1和100之间
书
我的问题是这样的-
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 included列EndIP上创建包含索引
在EndIP包含列StartIP上创建包含索引
在StartIP、EndIP上创建索引
有人能为我推荐一些实现这一点的方法吗?如果您希望每本书都有一个书架价值,您可以尝试:
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;
这应该有效地利用ShelveRangeStart、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;
如果其他假设是正确的,这可能会解决您的问题
编辑二:
如果需要其他属性,请尝试交叉应用。它应具有类似的性能特征:
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
但是,这可能会混淆优化引擎并阻止索引的使用。如果行得通,那太好了。如果它不起作用,我建议使用第一个版本,每个变量都有一个案例。或者,使用相关子查询版本并在主键上连接回搁置表。您的查询返回一行还是多行?欢迎使用StackOverflow:如果您发布代码、XML或数据示例,请在文本编辑器中突出显示这些行,然后单击“代码示例”按钮{}在编辑器工具栏上很好地格式化和语法突出显示它!为什么不将指定的ShelveID存储在book表中?这就是属性所属的位置,因为Book和Shelve之间的关系为零或一。非规范化设计是性能问题的根本原因,因为从性能角度来看,连接一个不等式运算符是有问题的。@Gordon Linoff此查询运行多行。每本书一行。@Dan-我们必须每三天左右更改一次书的位置,并且书架表由密码填充。书架表定期更改,因此我们无法在书表中存储shelveID。我们可以优化阅读部分。是的,书籍范围不重叠。这是在线书店的实际应用程序。这里有一个问题。bookID可能不存在于任何给定范围之间。在这种情况下,我必须返回null。在给定的情况下,bookid150的shevleID应该为空。非常感谢。这种方法显示了良好的性能改进。只是一个小问题。除了shelve表中的ShelveID之外,我还需要获得一些其他属性。将此结果与搁置表连接是获得此结果的唯一方法还是有更好的方法?我想要书。*,ShelveID,ShelveName,ShelveServerID。。。。。。。。resultCase语句中的列仍然忽略了不在任何rangeMy bad范围内的BookID—实际上是将ORDER BY s.RangeStart更改为ORDER BY s.RangeStart DESC。
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