2016-11-10 96 views
1

我正在运行下面的查询以基于同一个表内的日期字段检索唯一的最新结果。但是当这个表增长时,这个查询需要很多时间。任何改善这一点的建议都是值得欢迎的。查询运行时间过长

select 
    t2.* 
from 
    (
     select 
      (
       select 
        id 
       from 
        ctc_pre_assets ti 
       where 
        ti.ctcassettag = t1.ctcassettag 
       order by 
        ti.createddate desc limit 1 
      ) lid 
     from 
      (
       select 
        distinct ctcassettag 
       from 
        ctc_pre_assets 
      ) t1 
    ) ro, 
    ctc_pre_assets t2 
where 
    t2.id = ro.lid 
order by 
    id 

我们能够多次包含相同的行,但每行都有不同的时间戳。我的对象基于单个列,例如assettag我想用最新的时间戳检索每个assettag的单行。

+4

请提供表格定义和EXPLAIN输出。 –

+1

你有没有试过使用索引? – Dezigo

+0

添加索引后就没事了,但仍然很慢。花费超过20秒 – Rajesh

回答

0

找到每个ctcassettag的最新日期然后重新找回匹配的整个行更简单并且可能更快。

这并假设没有ctcassettag具有相同createddate多行,在这种情况下,你可以拿回超过每ctcassettag一行。

SELECT 
    ctc_pre_assets.* 
FROM 
    ctc_pre_assets 
INNER JOIN 
(
    SELECT 
     ctcassettag, 
     MAX(createddate) AS createddate 
    FROM 
     ctc_pre_assets 
    GROUP BY 
     ctcassettag 
) 
    newest 
     ON newest.ctcassettag = ctc_pre_assets.ctcassettag 
     AND newest.createddate = ctc_pre_assets.createddate 
ORDER BY 
    ctc_pre_assets.id 

编辑:处理与同一日期的多个行。

你还没有真正说过如何在同一createddate上多行同一ctcassettag的情况下选择你想要的行。所以,这个解决方案只是从duplicates中选择最低的id这一行。

SELECT 
    ctc_pre_assets.* 
FROM 
    ctc_pre_assets 
WHERE 
    ctc_pre_assets.id 
    = 
    (
     SELECT 
      lookup.id 
     FROM 
      ctc_pre_assets lookup 
     WHERE 
      lookup.ctcassettag = ctc_pre_assets.ctcassettag 
     ORDER BY 
      lookup.createddate DESC, 
      lookup.id   ASC 
     LIMIT 
      1 
    ) 

但这仍然使用相关子查询,这比简单的嵌套子查询慢(如我的第一个答案),但它处理的“副本”。

您可以通过更改相关子查询中的ORDER BY来更改要选择的行的规则。

它也非常类似于您自己的查询,但少一个连接。

+0

谢谢。但如果时间完全匹配,则查询将返回重复值。但我只想单独进入。 – Rajesh

+0

你能帮忙吗? – Rajesh

+0

@Rajesh - 那么你应该回答我对数据的评论;)另外,我相信他们不会重复,他们会有不同的'id'。所以,问题就变成了,你怎么选择要返回哪一行呢?如果两行用于相同的'ctcassettag'并且具有相同的'createddate',*您想要哪一个*? – MatBailie

0

嵌套查询总是比传统查询花费更长的时间,因为。你可以追加'解释'在查询的开始,并把你的结果在这里?这将有助于我们分析确切的查询/表格,这些查询/表格的响应时间更长。

检查表是否有索引。不可缩进的表是不可取的(除非显然需要不缩进),并且执行查询的速度惊人地慢。

相反,我认为最好的情况是避免完全编写嵌套查询。 Bette,分别运行每个查询,然后在第二个查询中使用结果(数组或列表格式)。

+1

这应该可能是一个评论,而不是一个答案。 –

+0

表已经有索引。正如你所建议的,让我试着执行单独的查询。 – Rajesh

+1

嵌套查询不需要更长的执行时间或更昂贵的解释计划。这种信念往往是由于不理解解释计划是如何产生的。缺乏知识意味着编写性能不佳的查询并不知道为什么很容易。例如'SELECT * FROM(SELECT * FROM tbl WHERE x = 1)AS x1 WHERE y = 2'将执行与使用SELECT * FROM tbl WHERE x = 1 AND y = 2'相同的操作。总而言之,嵌套查询的执行效果不好,因为它们包含混淆索引的计算或者写得不好,不仅仅是因为它们是嵌套的。 – MatBailie

0

一是一些问题,你至少应该问问自己,但也许也给我们一个答复,以改善我们的反应的准确性:

  1. 是您的数据标准化?如果是的话,也许你应该例外以避免这个残酷的子查询问题
  2. 你使用的是索引吗?如果是的话,哪一个,你是否充分利用它们?

一些建议,以提高可读性,也许性能查询: - 由 使用群体 - - 使用加入 使用聚合

例(未经测试,因此可能无法正常工作,但应该给的印象):

SELECT t2.* 
FROM (
    SELECT id 
    FROM ctc_pre_assets 
    GROUP BY ctcassettag 
    HAVING createddate = max(createddate) 
    ORDER BY ctcassettag DESC 
) ro 
INNER JOIN ctc_pre_assets t2 ON t2.id = ro.lid 
ORDER BY id 

使用正常化是伟大的,但也有地方正常化导致弊大于利的几个注意事项。这看起来像这样的情况,但如果没有我的表格,我无法确定。

使用截然不同的方式,我不禁得到你可能得不到所有相关结果的感觉 - 也许别人可以证实或否认这一点?

这并不是说子查询都不好,但如果写入不正确,它们往往会产生大规模的可伸缩性问题。确保你使用正确的方式(谷歌吗?)

索引可以为您节省一堆时间 - 如果你真的使用它们。设置它们还不够,您必须创建实际使用索引的查询。 Google也是如此。

+1

你的内部查询('ro')使用'LIMIT 1',因此只能返回一行。然而,Op的查询返回一行***,每个***独特的'ctcassettag'。 – MatBailie

+0

@MatBailie你绝对是对的,滑了我的脑海。但是完全删除LIMIT 1会返回正确的结果吗? –

+0

我不得不尝试看看,但可能由于MySQL中的某些行为。你可能需要'ORDER BY MAX(createddate)'或类似的东西,我不确定没有尝试它。但最相关的是这种行为是否保证是确定性的,事实并非如此。虽然这个“诀窍”几乎一直都在运作,但文件确实表明,你实际上不能*依靠它*总是*工作。事实上它明确表示它是“不确定的”。 – MatBailie