sql-server - SQL 服务器 : How should I structure my index to improve lookup time?

标签 sql-server database indexing database-design database-optimization

我有一个存储城市 IP 地址范围的表,该表中有数百万条记录。我敢肯定你们中许多处理 IP 地址的人都有一个与我相似的表(我在这个例子中简化了我的表):

CREATE TABLE [dbo].[IPRangeByCity]
(
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [IPIntegerStart] [bigint] NOT NULL,
    [IPIntegerEnd] [bigint] NOT NULL,
    [Country] [nvarchar](150) NOT NULL,
    [City] [nvarchar](150) NULL

    CONSTRAINT [pk_IPRangeByCity] 
        PRIMARY KEY CLUSTERED([ID] ASC),
) ON [PRIMARY]
 GO

现在我不保存、更新或删除该表中的任何记录。我只从这张 table 上读到。当我从这个表中读取时,我获取一个 IPv4 地址,将其转换为整数形式,并使用 IPv4 地址的整数形式,我在 IP 地址范围内查找该整数的城市。

例如,假设 IPv4 地址是“187.245.227.116”。

“187.245.227.116”转换为整数 3153453940。然后我运行以下选择语句来查找与此 IP 地址关联的城市:

select * from IPRangeByCity 
where 3153453940 between IPIntegerStart and IPIntegerEnd

我的问题是,如果我只使用上面的 select 语句从这个表中读取,我应该如何构建我的索引以缩短 select 语句的查找时间?

在我的脑海中,如果我将此表的索引设置为“IPIntegerStart”列,它似乎是我的 select 语句的一个很好的索引。例如:

CONSTRAINT [pk_IPRangeByCity] PRIMARY KEY CLUSTERED([IPIntegerStart] ASC)

不过,我不太确定。根据我的选择语句,有人知道为我的表设置的最佳索引是什么吗?它应该是聚簇索引还是非聚簇索引?它应该是多列索引(即同时包含 IPIntegerStart 和 IPIntegerEnd 列的索引)吗?任何帮助,将不胜感激。谢谢。

编辑:我可以在我的表中创建任何主键。在此示例中,我将主键设置为 ID 和身份键。但是我可以将主键更改为任何列,只要我的 select 语句运行速度快,这就是我所关心的。

最佳答案

编辑:在一些细节为人所知之后,之前的答案就一文不值了。看来你最初的想法可能是正确的:

alter table dbo.IPRangeByCity add constraint [PK_IPRangeByCity]
primary key (IPIntegerStart);

但是,您还需要在 IPIntegerEnd 上使用非聚集索引。下面是一些解释。

首先,范围之间没有重叠并且 Id 列是伪造的,您可以将主键替换为指定的主键。 PK 默认是集群的,所以它会使得查找和扫描更快。

其次,正如 Martin Smith 在评论中正确指出的那样,使用 between 谓词或类似逻辑的直接查询将发生大型索引扫描。但是,我认为这不是问题,因为没有范围重叠,这意味着任何 IP 地址最多只能属于 1 个范围。因此,搜索查询可以重写如下:

select top (1) r.*
from dbo.IPRangeByCity r
where 3153453940 between r.IPIntegerStart and r.IPIntegerEnd
order by r.IPIntegerStart desc;

这样,它应该总是足够快,因为聚簇索引扫描要么在找到第一个合适的行后停止,要么被 IPIntegerEnd 中断。请注意,这纯属推测,您应该根据与您的产品相当的数据量进行核对。

不过,我不会放弃类似于 Jack Douglas 的非规范化方法(虽然我不能说我理解它)。我什至不会放弃创建所有可能的 IPv4 地址的完整列表并搜索它的可能性——它实际上并不像听起来那么荒谬。最终,这一切都取决于细节。

关于sql-server - SQL 服务器 : How should I structure my index to improve lookup time?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40958730/

相关文章:

sql-server - SQL Server - 带长度截断的字符串分隔

mysql - 数据库中是否需要将域名存储为md5模式?

mongodb - 具有大量类似 sql 连接的查询的数据库设计

PHP:如何将变量动态分配到数组中

oracle - 在空表中执行缓慢的查询。 (删除大量插入后)

sql-server - CASE 语句中随机生成的值返回 NULL

sql - 如何找到始终包含确切数量的字符类型的子字符串?

SQL不允许将日期列转换为日期时间?

php - [PHP + MySQL]数据库SELECT查询未返回结果

在列表中查找最大值(和索引)的 Pythonic 方法