【问题标题】:What would be a good way to write this SQL query in a better way?以更好的方式编写此 SQL 查询的好方法是什么?
【发布时间】:2013-06-18 18:26:12
【问题描述】:
SELECT
    MAX(timestamp) as end,
    MIN(timestamp) as start, 
    (MAX(odometerKM) - MIN(odometerKM)) as distanceTravelled,
    ( SELECT COUNT(*) FROM EventData WHERE speedKPH = 0 AND timestamp >= ? AND timestamp <= ? AND  deviceID = ?)  as stopsDuration,
    ( SELECT COUNT(*) FROM EventData WHERE speedKPH != 0 AND timestamp >= ? AND timestamp <= ? AND  deviceID = ? )  as tripDuration,
    (MAX(odometerKM) - MIN(odometerKM)) / ( SELECT fuelEconomy FROM Device WHERE deviceID = ?) as fuelConsumption
FROM EventData
WHERE deviceID = ? AND timestamp >= ? AND timestamp <= ?

相当混乱,但我创建了这个查询来查找一组行的摘要。最小和最大时间戳很简单,但要找到速度为零而不是零的行数,我做了一个丑陋的 hack。我确定有更好的方法来做到这一点?

更新:“?”指代被 CodeIgniter 的一个不成熟的查询生成器所取代。遗憾的是,它还不支持命名参数。

【问题讨论】:

  • 您没有忘记在前两个子查询中包含条件WHERE deviceID = ? 吗?
  • @Yak:是的。让我编辑。
  • 另外,看起来相同的两个子查询实际上计算的是 number 个事件 (COUNT()) 而不是持续时间?

标签: mysql optimization query-optimization


【解决方案1】:

您应该包含 DeviceID,这样才有意义。试试这个:

SELECT
DeviceID,
MAX(timestamp) as end,
MIN(timestamp) as start, 
(MAX(odometerKM) - MIN(odometerKM)) as distanceTravelled,
SUM (
  case speedKPH 
    when  0  then 1
    else 0
  end)  as stopsDuration,

SUM (
  case speedKPH 
    when  0  then 0
    else 1
  end)  as tripDuration,

(MAX(odometerKM) - MIN(odometerKM)) / Device.fuelEconomy  as fuelConsumption

FROM EventData
Join Device ON Device.deviceID = EventData.deviceID 

WHERE deviceID = ? AND timestamp >= ? AND timestamp <= ?

GROUP BY  DeviceID

【讨论】:

    【解决方案2】:

    我会摆脱列子查询。您可以像这样计算stopsDurationtripDuration(我暂时省略fuelConsumption):

    SELECT
      MAX(timestamp) as end, MIN(timestamp) as start, 
      MAX(odometerKM) - MIN(odometerKM) as distanceTravelled,
      COUNT(speedKPH = 0 AND timestamp >= ? AND timestamp <= ?) as stopsDuration
      COUNT(speedKPH != 0 AND timestamp >= ? AND timestamp <= ?) as tripDuration
    FROM EventData WHERE deviceID = ? AND timestamp >= ? AND timestamp <= ?
    

    您可以通过交叉连接到Device 表的单个适用行来摆脱fuelComparison 子查询

    SELECT
      (MAX(odometerKM) - MIN(odometerKM)) / dv.fuelEconomy as fuelConsumption
    FROM
      EventData,
      (SELECT Device.fuelEconomy FROM Device WHERE DeviceId = ?) dv
    WHERE deviceID = ? AND timestamp >= ? AND timestamp <= ?
    

    把它们放在一起,你就会得到这个,(至少在纸上)应该更快:

    SELECT
      MAX(timestamp) as end, MIN(timestamp) as start, 
      MAX(odometerKM) - MIN(odometerKM) as distanceTravelled,
      COUNT(speedKPH = 0 AND timestamp >= ? AND timestamp <= ?) as stopsDuration
      COUNT(speedKPH != 0 AND timestamp >= ? AND timestamp <= ?) as tripDuration,
      (MAX(odometerKM) - MIN(odometerKM)) / dv.fuelEconomy as fuelConsumption
    FROM
      EventData,
      (SELECT Device.fuelEconomy FROM Device WHERE DeviceId = ?) dv
    WHERE deviceID = ? AND timestamp >= ? AND timestamp <= ?
    

    【讨论】:

    • 为了进一步减少,创建另一个带有 WHERE 条件的子查询表并完全消除 WHERE 不是更好吗?
    • 我想过这个问题,但我不确定它是否会破坏start 和/或end 和/或distanceTravelled 值。我从来没有打算测试这个,所以我在做了我 100% 确定的事情之后就停下来了。如果您可以将其减少到那么远,那么您绝对应该将其发布为答案。随意使用我的查询作为起点 - 我对此没有任何问题:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多