0

我有一张桌子在下面。

在此处输入图像描述

在以下查询中,外部查询将列与子查询的like比较连接起来。tag

 SELECT top 6 *
  FROM [piarchive].[picomp2]
  WHERE tag Like
  (
  Select distinct left(tag,19) + '%' 
  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 order by time desc) as t1
  )  
  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

但是这个子查询返回多行,导致以下错误:

错误:“当用作表达式时,子查询最多可以返回一行。”

4

1 回答 1

1

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% 的速度提高),尽管我只是针对我敲出的几百行测试数据运行这个。你拥有的数据越多,它应该越有效。

于 2014-10-02T09:03:44.550 回答