Sql 2列上的范围查询

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的书。 然后

我有一个非常大的书架,大约有1亿个,上面有书架信息

搁置

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