将where tag like (...)
(...
子查询在哪里,为简洁起见,此处省略)部分替换为where exists (...)
,并将like
比较带入子查询。
select top 6
*
from
[piarchive].[picomp2] t0
where
exists
(
select
*
from
(
select
*
from
[piarchive].[picomp2]
where
tag like '%cpu_active' and time between '2014/10/02 15:13:08' and '2014/10/02 15:18:37'
and
value = -524289
)
as t1
where
t0.tag like left(t1.tag, 19) + '%'
)
and
tag not like '%cpu_active'
and
tag not like '%program%'
and
time between '2014/10/02 15:13:08' and '2014/10/02 15:18:37'
order by
time desc;
我在外部查询中添加了一个表别名来消除tag
列的歧义,但是您可以看到like
比较已转移到子查询中。
我不能保证这将如何在大型数据集上执行,但这是一个不同的话题。就个人而言,我会寻找一种完全摆脱子查询的方法,因为它都在查询同一个表。
更多关于优化
优化并不容易,索引在这里用处不大,原因如下:
- 连接条件 (
t0.tag like left(t1.tag, 19) + '%'
) 并不简单,查询优化器可能很难产生比嵌套循环更好的东西(即,为外部查询的每一行执行子查询)。这可能是您最大的性能杀手。
- 没有一个
like
比较可以利用表索引,因为它们检查的是值的结尾,而不是开始。
您唯一的希望可能是日期范围检查是否具有高度选择性(消除大量记录)。由于time
在外部和内部查询中都对字段执行相同的检查,因此您可以将其选择到临时表中:
select left(tag, 19) as key, *
into #working
from [piarchive].[picomp2]
where [time] between '2014/10/02 15:13:08' and '2014/10/02 15:18:37';
#working
现在只有指定时间段内的记录。由于您的示例范围很窄(只有 5 1/2 分钟),我敢打赌这可能会淘汰约 99% 的记录。上的索引time
将大大加快这一进程。完成此操作后,您只需要处理一小部分数据。
然后,可能(见下文)索引key
:
create clustered index cx_key on #working (key);
然后完成查询的其余部分:
select a.*
from #working a
where exists
(
select *
from #working b
where a.key = b.key and b.tag like '%cpu_active'
)
and
a.tag not like '%program%'
and
a.tag not like '%cpu_active'
我所做的是在连接条件(的前 19 个字符tag
)上创建一个聚集索引来优化子查询。您必须对此进行测试,因为如果首先创建索引的成本超过收益,它可能没有任何区别,甚至会减慢速度。这将取决于您拥有多少数据以及其他因素。这样做我只获得了最小的收益(大约 5% 的速度提高),尽管我只是针对我敲出的几百行测试数据运行这个。你拥有的数据越多,它应该越有效。