【问题标题】:Is it possible to create a non clustered index on column length or any sql function是否可以在列长度或任何 sql 函数上创建非聚集索引
【发布时间】:2016-12-02 13:18:23
【问题描述】:

我在这个网站上搜索过类似的问题,但我没有找到答案,我确定它在某个地方但我没有找到它,我的问题是,我有一个名为 Maps 的表,该表包含数百万行,并且该表具有索引: imagename 列上的 ClusteredIndex 和 imagename 列和 downloaded 列上的 NonClusteredIndex,

以下查询需要 0 来执行:

SELECT top 100 imagename 
from [maps] 
where imagename='SomeExistingImageName' 
and downloaded is null

结果 ->100 行

此外,以下查询需要 0 来执行:

SELECT top 100 imagename 
from [maps] 
where imagename='SomeRandomNameThatDoesNotExistOnMyDatabase' 
and donwloaded is null

结果 ->0 行

但是当我尝试运行以下查询时,执行需要 02min08s:

SELECT top 100 imagename 
from [maps] 
where LEN(imagename)=10
and downloaded is null

结果 -> 0rows(因为没有满足这些条件的图像名称)

另一个例子,当我将 10 更改为 17 时,执行需要 0 秒:

SELECT top 100 imagename 
from [maps] 
where LEN(imagename)=17
and downloaded is null

结果 ->100 行

我的问题是什么是提高这种查询(具有列长度的查询)性能的最佳方法?是否可以在 LEN(imagename) 上创建另一个 NonClusteredIndex ?如果答案是肯定的,应该涉及哪些列?

PS : 我的表包含超过 5 亿个条目

【问题讨论】:

  • 您在寻找Function-based indexes吗?
  • 我认为您可以添加一个计算列来保持图像名称的长度并为计算列设置索引。

标签: sql sql-server


【解决方案1】:

你可以使用虚拟列

alter table [maps] add len_imagename as (len(imagename))
create index maps_ix_len_imagename on [maps] (len_imagename)

演示

;with t(i) as (select 1 union all select i+1 from t where i<10)
select  replicate('x',rand(cast(newid() as varbinary))*1000)    AS i
into    #t
from    t t0,t t1,t t2,t t3,t t4,t t5,t t6
option  (maxrecursion 0)

alter table #t add len_i as (len(i))

create index #t_ix_len_i on #t (len_i)

select count(*) from #t where len_i between 99 and 101

【讨论】:

  • 我的想法完全正确。我花了太长时间来测试:-)
  • 这个新索引将只应用于 len_imagename ?这个新索引不应该涉及 imagename 和下载的列?
  • 我要么将其设为过滤索引 - create index maps_ix_len_imagename on [maps] (len_imagename) where downloaded is null;,要么将 downloaded 作为非键列 - create index maps_ix_len_imagename on [maps] (len_imagename) include(downloaded); 以避免键查找。
  • 只是演示概念还没有通过主题:-)
  • 哪个最好取决于您正在运行的查询。过滤后的索引更小,维护开销更少,但通用性较差,因此取决于您的需求;如果像您的问题一样,您的所有查询都排除了带有and downloaded is null 的非空记录,那么过滤索引就足够了,如果您有更多不同的查询,那么包括downloaded 作为键或非键列。这里没有正确或错误的选择,只是一个或多或少合适的选择,但只有你知道哪个是哪个。
【解决方案2】:

这个对我有用:

alter table [maps] add len_imagename as (len(imagename));
create index [maps] on [maps] (len_imagename) include([downloaded]);

以下查询现在的执行时间是0s:

SELECT top 100 imagename 
from [maps] 
where LEN(imagename)=10
and downloaded is null

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-20
    • 1970-01-01
    • 1970-01-01
    • 2018-08-09
    • 1970-01-01
    • 1970-01-01
    • 2021-01-14
    • 2017-05-08
    相关资源
    最近更新 更多