0

关于我的问题,我有一个非常复杂的答案:

选择一条记录,只要它之前的值较低

大约 3 周前。

现在我对更改此查询感到困扰。

所以这是这个查询的最终版本:

SELECT  a.ID, DATE_FORMAT(a.Time,'%d/%m/%y') AS T, a.SerialNumber, 
    b.Remain_Toner_Black BeforeCount,
    a.Remain_Toner_Black AfterCount
FROM    
    (
        SELECT  a.ID, 
                a.Time, 
                a.SerialNumber, 
                a.Remain_Toner_Black,
                (
                    SELECT  COUNT(*)
                    FROM    Reports c
                    WHERE   c.SerialNumber = a.SerialNumber AND
                            c.ID <= a.ID) AS RowNumber
        FROM    Reports a
    ) a
    LEFT JOIN
    (
        SELECT  a.ID, 
                a.Time, 
                a.SerialNumber, 
                a.Remain_Toner_Black,
                (
                    SELECT  COUNT(*)
                    FROM    Reports c
                    WHERE   c.SerialNumber = a.SerialNumber AND
                            c.ID <= a.ID) AS RowNumber
        FROM    Reports a
    ) b ON a.SerialNumber = b.SerialNumber AND
            a.RowNumber = b.RowNumber + 1
WHERE b.Remain_Toner_Black < a.Remain_Toner_Black AND b.Remain_Toner_Black >= 0

大约需要0.0002秒才能完成。

我想要的是编辑这个查询的最后一行,所以它是:

WHERE month(a.Time) = ".$i." AND b.Remain_Toner_Black < a.Remain_Toner_Black AND b.Remain_Toner_Black >= 0

但是,查询大约需要6.9047秒才能完成。

我怎样才能添加这个: month(a.Time) = ".$i." 以最省时的方式查询?

4

3 回答 3

1

对此进行调查,以下方法可能是比您已经使用的更快的基本选择方法:-

SELECT AfterSub.ID, 
    AfterSub.SerialNumber, 
    BeforeSub.Remain_Toner_Black BeforeCount,
    AfterSub.Remain_Toner_Black AfterCount
FROM
(
    SELECT ID, SerialNumber, Remain_Toner_Black, @Counter1:=@Counter1+1 AS SeqCnt
    FROM TableName
    CROSS JOIN (SELECT @Counter1:=0) Sub1
    ORDER BY SerialNumber, ID
) AfterSub
INNER JOIN
(
    SELECT ID, SerialNumber, Remain_Toner_Black, @Counter2:=@Counter2+1 AS SeqCnt
    FROM TableName
    CROSS JOIN (SELECT @Counter2:=1) Sub2
    ORDER BY SerialNumber, ID
) BeforeSub
ON BeforeSub.SerialNumber = AfterSub.SerialNumber
AND BeforeSub.SeqCnt = AfterSub.SeqCnt
WHERE   AfterSub.Remain_Toner_Black > BeforeSub.Remain_Toner_Black
ORDER BY AfterSub.SerialNumber, AfterSub.ID

在这里检查月份的问题是以下项目可能在不同的月份,这取决于计数。

你可以试试:-

SELECT AfterSub.ID, 
    AfterSub.SerialNumber, 
    BeforeSub.Remain_Toner_Black BeforeCount,
    AfterSub.Remain_Toner_Black AfterCount
FROM
(
    SELECT ID, SerialNumber, Remain_Toner_Black, @Counter1:=@Counter1+1 AS SeqCnt
    FROM TableName
    CROSS JOIN (SELECT @Counter1:=0) Sub1
    ORDER BY SerialNumber, ID
) AfterSub
INNER JOIN
(
    SELECT ID, SerialNumber, Remain_Toner_Black, @Counter2:=@Counter2+1 AS SeqCnt
    FROM TableName
    CROSS JOIN (SELECT @Counter2:=1) Sub2
    ORDER BY SerialNumber, ID
) BeforeSub
ON BeforeSub.SerialNumber = AfterSub.SerialNumber
AND BeforeSub.SeqCnt = AfterSub.SeqCnt
AND AfterSub.Remain_Toner_Black > BeforeSub.Remain_Toner_Black
WHERE month(BeforeSub.Time) = ".$i." 
ORDER BY AfterSub.SerialNumber, AfterSub.ID

但这不会使用索引(但我希望行数很低,所以我希望不是问题)。

您可以选择获取序列号,然后只检查该月的项目,然后再加入下个月:-

SELECT AfterSub.ID, 
    AfterSub.SerialNumber, 
    BeforeSub.Remain_Toner_Black BeforeCount,
    AfterSub.Remain_Toner_Black AfterCount
FROM
(
    SELECT ID, SerialNumber, Remain_Toner_Black, @Counter1:=@Counter1+1 AS SeqCnt
    FROM TableName
    CROSS JOIN (SELECT @Counter1:=0) Sub1
    ORDER BY SerialNumber, ID
) AfterSub
INNER JOIN
(
    SELECT ID, SerialNumber, Remain_Toner_Black, SeqCnt
    FROM
    (
        SELECT ID, SerialNumber, Remain_Toner_Black, `Time`, @Counter2:=@Counter2+1 AS SeqCnt
        FROM TableName
        CROSS JOIN (SELECT @Counter2:=1) Sub2
        ORDER BY SerialNumber, ID
    ) BeforeSub
    WHERE month(BeforeSub.Time) = ".$i." 
) BeforeSub
ON BeforeSub.SerialNumber = AfterSub.SerialNumber
AND BeforeSub.SeqCnt = AfterSub.SeqCnt
AND AfterSub.Remain_Toner_Black > BeforeSub.Remain_Toner_Black
ORDER BY AfterSub.SerialNumber, AfterSub.ID

(注意,最后 2 个选择都没有经过测试)

编辑

为 2 个子选择添加年/月检查。但是,由于日期被格式化以进行此检查,我不确定索引是否有用:-

SELECT AfterSub.ID, 
    AfterSub.SerialNumber, 
    BeforeSub.Remain_Toner_Black BeforeCount,
    AfterSub.Remain_Toner_Black AfterCount
FROM
(
    SELECT ID, SerialNumber, Remain_Toner_Black, @Counter1:=@Counter1+1 AS SeqCnt
    FROM TableName
    CROSS JOIN (SELECT @Counter1:=0) Sub1
    WHERE DATE_FORMAT(`Time`,'%Y %m') >= '2013 01' 
    ORDER BY SerialNumber, ID
) AfterSub
INNER JOIN
(
    SELECT ID, SerialNumber, Remain_Toner_Black, `Time`, @Counter2:=@Counter2+1 AS SeqCnt
    FROM TableName
    CROSS JOIN (SELECT @Counter2:=1) Sub2
    WHERE DATE_FORMAT(`Time`,'%Y %m') = '2013 01' 
    ORDER BY SerialNumber, ID
) BeforeSub
ON BeforeSub.SerialNumber = AfterSub.SerialNumber
AND BeforeSub.SeqCnt = AfterSub.SeqCnt
AND AfterSub.Remain_Toner_Black > BeforeSub.Remain_Toner_Black
ORDER BY AfterSub.SerialNumber, AfterSub.ID

在子选择中使用日期(这意味着计算该月的最后一天)可能更有效:-

SELECT AfterSub.ID, 
    AfterSub.SerialNumber, 
    BeforeSub.Remain_Toner_Black BeforeCount,
    AfterSub.Remain_Toner_Black AfterCount
FROM
(
    SELECT ID, SerialNumber, Remain_Toner_Black, @Counter1:=@Counter1+1 AS SeqCnt
    FROM TableName
    CROSS JOIN (SELECT @Counter1:=0) Sub1
    WHERE `Time` >= '2013-01-01' 
    ORDER BY SerialNumber, ID
) AfterSub
INNER JOIN
(
    SELECT ID, SerialNumber, Remain_Toner_Black, `Time`, @Counter2:=@Counter2+1 AS SeqCnt
    FROM TableName
    CROSS JOIN (SELECT @Counter2:=1) Sub2
    WHERE `Time` BETWEEN '2013-01-31' AND '2013-01-31'
    ORDER BY SerialNumber, ID
) BeforeSub
ON BeforeSub.SerialNumber = AfterSub.SerialNumber
AND BeforeSub.SeqCnt = AfterSub.SeqCnt
AND AfterSub.Remain_Toner_Black > BeforeSub.Remain_Toner_Black
ORDER BY AfterSub.SerialNumber, AfterSub.ID
于 2013-10-03T12:37:02.153 回答
0

请在 A.time 上放置索引并使用它

SELECT  a.ID, DATE_FORMAT(a.Time,'%d/%m/%y') AS T, a.SerialNumber, 
    b.Remain_Toner_Black BeforeCount,
    a.Remain_Toner_Black AfterCount
FROM    
    (
        SELECT  a.ID, 
                a.Time, 
                a.SerialNumber, 
                a.Remain_Toner_Black,
                month(a.time) as Month
                (
                    SELECT  COUNT(*)
                    FROM    Reports c
                    WHERE   c.SerialNumber = a.SerialNumber AND
                            c.ID <= a.ID) AS RowNumber
        FROM    Reports a
    ) a
    LEFT JOIN
    (
        SELECT  a.ID, 
                a.Time, 
                a.SerialNumber, 
                a.Remain_Toner_Black,
                (
                    SELECT  COUNT(*)
                    FROM    Reports c
                    WHERE   c.SerialNumber = a.SerialNumber AND
                            c.ID <= a.ID) AS RowNumber
        FROM    Reports a
    ) b ON a.SerialNumber = b.SerialNumber AND
            a.RowNumber = b.RowNumber + 1
WHERE a.month = ".$i." AND b.Remain_Toner_Black < a.Remain_Toner_Black AND b.Remain_Toner_Black >= 0`
于 2013-10-03T12:11:14.083 回答
0

我不确定这个答案是否能解决你的问题,但我认为如果你附加这个条件 month(a.Time) = ".$i." 在两个子查询(即子查询“a”和子查询“b”)中,它可能有助于提高查询的性能。

于 2013-10-03T12:14:37.013 回答