2013-09-27 21 views
-1

我一直在玩弄于天,这个查询条件和限制较少,MySQL的没有完成的执行比巨大的表

select slno,Power_Factor_L32_Avg 
from power_logger pl 
where (pl.slno between 1851219 and 2042099) 
    and meter_id="logger1" 
    and pl.Power_Factor_L32_Avg is not null 
    and case when (((pl.slno=1851219) 
       and ((pl.Power_Factor_L32_Avg) not between 0.400 and 1.000)) 
      or ((pl.slno=2042099) and 
       ((pl.Power_Factor_L32_Avg) not between 0.400 and 1.000)) 
      or ((pl.Power_Factor_L32_Avg not between 0.400 and 1.000) and 
       (((select p2.Power_Factor_L32_Avg 
        from power_logger p2 
        where p2.slno=(select slno 
           from power_logger 
           where slno>pl.slno 
            and Power_Factor_L32_Avg is not null 
           order by slno asc limit 1)) 
       between 0.400 and 1.000) 
      or ((select p4.Power_Factor_L32_Avg 
        from power_logger p4 
        where p4.slno=(select slno 
           from power_logger 
           where slno<pl.slno 
            and Power_Factor_L32_Avg is not null 
           order by slno desc limit 1)) 
       between 0.400 and 1.000)))) 
      then (case when (((pl.slno=1851219) 
         and ((select p10.Power_Factor_L32_Avg 
           from power_logger p10 
           where p10.slno=pl.slno+1) is null 
          or (select p10.Power_Factor_L32_Avg 
           from power_logger p10 
           where p10.slno=pl.slno+1) between 0.400 and 1.000)) 
         or (((select p5.Power_Factor_L32_Avg 
           from power_logger p5 
           where p5.slno=(select slno 
              from power_logger 
               where slno<pl.slno 
               and Power_Factor_L32_Avg is not null 
               order by slno desc limit 1)) 
           between 0.400 and 1.000) 
          and ((select p6.Power_Factor_L32_Avg 
           from power_logger p6 
           where p6.slno=(select slno 
               from power_logger 
               where slno>pl.slno 
               and Power_Factor_L32_Avg is not null 
               order by slno asc limit 1)) 
           between 0.400 and 1.000))) 
         then 0=1 
         else 1 
         end) 
      else 0=1 
      end 
order by slno asc 

这将是很难理解在查询但是它正在查询一张拥有数百万条记录的表格。这里唯一的问题是嵌套查询“select slno from power_logger where slno<pl.slno and Power_Factor_L32_Avg is not null order by slno desc limit 1”和“select slno from power_logger where slno>pl.slno and Power_Factor_L32_Avg is not null order by slno desc limit 1”,它用于查找分别具有非空值的当前记录的前一记录和下一记录的序列号(slno)。当这些查询本身运行时,它会在几微秒内给出序列号,但是当包含在上面的查询中时,它会弄乱整个事情,并且该过程需要被明确地杀死。 如果不使用嵌套查询,则上面的查询执行时间少于1.5秒,而是由下一个/前一个序列号替换,而不管它是否为空。

这不会去任何地方。感谢有人能帮助我。

通过使用临时表新建查询,

create temporary table temp(
    id int auto_increment 
    ,slno int 
    ,pf decimal(10,4) 
    ,primary key(id) 
); 

insert into temp(slno,pf) 
(select slno,Power_Factor_L32_Avg 
from power_logger 
where slno between 1851219 and 2042099 
and meter_id='logger1' 
and Power_Factor_L32_Avg is not null); 

select pl.slno,pl.Power_Factor_L32_Avg,t1.slno,t1.pf 
from power_logger pl 
left join temp t1 on t1.slno>pl.slno 
where pl.slno between 1851219 and 2042099 and pl.meter_id='logger1' 
and pl.Power_Factor_L32_Avg is not null; 

这是测试如果下slno其中功率因数为空与slno从power_logger表一起取出。这也不起作用。我不确定是否有任何其他解决方法可以在不使用大于号的情况下获得下一个slno

+0

尝试将它们更改为“SELECT TOP 1”,而不是在最后加上“LIMIT 1”。这可能是MySQL可以更好地优化这些子查询,然后你不会看到如此大的放缓。 – Hbcdev

+0

@Hbcdev:感谢您的快速回复。我得到了使用TOP 1的语法错误。我以前没有使用它,我想它只适用于transact sql。 – Rohith

+0

对不起,你是对的。 – Hbcdev

回答

0

做一些修改Hbcdev的答案,

select c.slno,c.Power_Factor_L32_Avg from (select p.slno as cur,a.slno as next,@s1 as prev,(@s1:=p.slno) from (select @s1:=0) d,power_logger p join (SELECT a.slno, @s AS prev, (@s := a.slno) ne from power_logger a,(SELECT @s:=0) c where a.slno between 1851219 and 2042099 and a.Power_Factor_L32_Avg is not null and a.meter_id='logger1') as a on a.prev=p.slno where p.slno between 1851219 and 2042099 and p.Power_Factor_L32_Avg is not null and p.meter_id='logger1')d ,power_logger c where c.slno=d.cur and (((c.slno=1851219 or c.slno=2042099) and (c.Power_Factor_L32_Avg not between 0.400 and 1.000)) or ((c.Power_Factor_L32_Avg not between 0.400 and 1.000) and (((select p2.Power_Factor_L32_Avg from power_logger p2 where p2.slno=d.next) between 0.4 and 1.000) or ((select p3.Power_Factor_L32_Avg from power_logger p3 where p3.slno=d.prev) between 0.4 and 1.000)))) and not (((c.slno=1851219) and ((select p10.Power_Factor_L32_Avg from power_logger p10 where p10.slno=c.slno+1) is null or (select p10.Power_Factor_L32_Avg from power_logger p10 where p10.slno=c.slno+1) between 0.400 and 1.000)) or (((select p5.Power_Factor_L32_Avg from power_logger p5 where p5.slno=d.prev) between 0.400 and 1.000) and ((select p6.Power_Factor_L32_Avg from power_logger p6 where p6.slno=d.next) between 0.400 and 1.000))) order by slno asc

这6秒得到执行。

0

我的意见是,你在案件陈述方面做了太多的工作。你也重复了很多工作。

首先,预先计算的这个结果在P1的每一行,并将其存储在一个临时表:

select slno 
from power_logger 
where slno<pl.slno 
    and Power_Factor_L32_Avg is not null 
order by slno desc limit 1 

在主与

create temporary table temp(
    slno int 
    ,other_slno int 
); 

INSERT INTO temp(slno, other_slno)(
SELECT main.slno, second.slno 
FROM power_logger main 
JOIN (SELECT other.slno FROM power_logger AS other 
     where other.slno< main.slno 
     and Power_Factor_L32_Avg is not null 
     order by other.slno desc limit 1) second 

); 

这样做,那么查询,做 SELECT _ FROM power_logger LEFT JOIN temp ON power_logger.slno = temp.slno LEFT JOIN power_logger other ON temp.other_slno = other.slno

这意味着,无论你目前使用类似

(select p4.Power_Factor_L32_Avg 
       from power_logger p4 
       where p4.slno=(select slno 
          from power_logger 
          where slno<pl.slno 
           and Power_Factor_L32_Avg is not null 
          order by slno desc limit 1) 

可以改为得到这个值作为òther.Power_Factor_L32_Avg

这会让您在每次使用时都快得多。临时表格上的信息很容易在Google上找到,例如。其次,在更简单的条件下只使用CASE语句。您当前的查询在相应的THEN语句中复制的某些WHEN语句内部具有布尔逻辑。这也是一个不好的迹象,CASE的结果是真实的还是错误的。

而是将布尔逻辑放在WHERE中。我从原始查询中复制并粘贴了下面的内容,因此它应该是正确的。

WHERE <Other clauses> .... 
    AND (
    ((pl.slno=1851219) 
      and ((pl.Power_Factor_L32_Avg) not between 0.400 and 1.000)) 
     or ((pl.slno=2042099) and 
      ((pl.Power_Factor_L32_Avg) not between 0.400 and 1.000)) 
     or ((pl.Power_Factor_L32_Avg not between 0.400 and 1.000) and 
      (((select p2.Power_Factor_L32_Avg 
       from power_logger p2 
       where p2.slno=(select slno 
          from power_logger 
          where slno>pl.slno 
           and Power_Factor_L32_Avg is not null 
          order by slno asc limit 1)) 
      between 0.400 and 1.000) 
     or ((select p4.Power_Factor_L32_Avg 
       from power_logger p4 
       where p4.slno=(select slno 
          from power_logger 
          where slno<pl.slno 
           and Power_Factor_L32_Avg is not null 
          order by slno desc limit 1)) 
      between 0.400 and 1.000))) 

    AND NOT 
     ((pl.slno=1851219) 
      and ((select p10.Power_Factor_L32_Avg 
        from power_logger p10 
        where p10.slno=pl.slno+1) is null 
       or (select p10.Power_Factor_L32_Avg 
        from power_logger p10 
        where p10.slno=pl.slno+1) between 0.400 and 1.000)) 
       or (((select p5.Power_Factor_L32_Avg 
       from power_logger p5 
        where p5.slno=(select slno 
           from power_logger 
            where slno<pl.slno 
            and Power_Factor_L32_Avg is not null 
            order by slno desc limit 1)) 
        between 0.400 and 1.000) 
       and ((select p6.Power_Factor_L32_Avg 
        from power_logger p6 
        where p6.slno=(select slno 
            from power_logger 
            where slno>pl.slno 
            and Power_Factor_L32_Avg is not null 
            order by slno asc limit 1)) 
        between 0.400 and 1.000)) 
) 

这应该有助于降低时间(尤其是使用临时表)。如果没有,则将新版本发布回SO,并且我们可以尝试用'JOIN's(这将再次更高效)替换一些子查询。

+0

非常感谢您的回复。不幸的是,通过将case语句更改为布尔逻辑,它只返回两行并占用更多的执行时间。另外,如果我们使用临时表,我们仍然必须使用select语句从临时表中选择slno,我认为它与当前查询的效果一样好。 – Rohith

+0

使用嵌套的select语句搞乱了整个事情。它通过所有的case语句以及通过用slno = pl.slno + 1/slno = pl.slno-1替换嵌套的select查询来完美执行。我真的必须使用嵌套选择,因为我需要power_factor_L32_Avg不为null的下一个slno,而pl.slno + 1或pl.slno-1中的power_factor_L32_Avg可能为null。 – Rohith

+0

使用临时表。它会比你现有的要快得多。临时表将保留在内存中,将停止查询重复工作,并将涉及更简单的查询来查找正确的行。尝试一下! – Hbcdev