以更好的方式编写此SQL查询的好方法是什么?

时间:2013-06-21 14:56:17

标签: mysql optimization query-optimization

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 <= ?

相当令人困惑,但我创建了此查询以查找行集的摘要。最小和最大时间戳很简单但是为了找到速度为零且不为零的COUNT行,我做了一个丑陋的黑客。我相信还有更好的方法吗?

更新:&#34;?&#34;引用由CodeIgniter的不成熟查询构建器替换。可悲的是,它还没有支持命名参数。

2 个答案:

答案 0 :(得分:0)

你应该包含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

答案 1 :(得分:0)

我将摆脱列子查询。您可以像这样计算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 <= ?

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

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 <= ?