考虑以下问题:
SELECT
nodos.nombre,
(SELECT super FROM atributo_16 WHERE nodoid=nodos.nodoid ORDER BY fecha DESC,created_at LIMIT 1) AS descuento_navision_super_cif,
(SELECT regular FROM atributo_16 WHERE nodoid=nodos.nodoid ORDER BY fecha DESC,created_at LIMIT 1) AS descuento_navision_regular_cif,
(SELECT diesel FROM atributo_16 WHERE nodoid=nodos.nodoid ORDER BY fecha DESC,created_at LIMIT 1) AS descuento_navision_diesel_cif
FROM
nodos
WHERE
nodos.nodotipoid=8;
这很好,但速度很慢。在此示例中,查询重复(3x)到同一个表并具有相同的WHERE。真正的查询有20种这样的子查询到不同的表。我想优化查询。
这是我尝试使用派生表加快速度的尝试之一。创建一个[fecha,created_at]索引,它提高了速度,但查询无法正常工作,因为查询的LIMIT 1部分在JOIN之前应用,我似乎无法添加WHERE语句的nodoid部分,可以解决问题。
SELECT
nodos.nombre,
descuentos.super AS descuento_navision_super_cif,
descuentos.regular AS descuento_navision_regular_cif,
descuentos.diesel AS descuento_navision_diesel_cif
FROM
nodos
LEFT JOIN (SELECT nodoid, super, regular, diesel, ulsd
FROM atributo_16 ORDER BY fecha DESC,
created_at LIMIT 1)descuentos ON descuentos.nodoid=nodos.nodoid
WHERE
nodos.nodotipoid=8
已更新 这是第一个查询的EXPLAIN表。
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY nodos ref nodotipoid nodotipoid 4 const 226
4 DEPENDENT SUBQUERY atributo_16 ref nodoid nodoid 4 nodos.nodoid 376 Using where; Using filesort
3 DEPENDENT SUBQUERY atributo_16 ref nodoid nodoid 4 nodos.nodoid 376 Using where; Using filesort
2 DEPENDENT SUBQUERY atributo_16 ref nodoid nodoid 4 nodos.nodoid 376 Using where; Using filesort
答案 0 :(得分:0)
尝试在派生表中使用变量来获取每组最大记录:
SELECT
nodos.nombre,
super AS descuento_navision_super_cif,
regular AS descuento_navision_regular_cif,
diesel AS descuento_navision_diesel_cif
FROM
nodos AS t1
LEFT JOIN (
SELECT super, regular, diesel, nodoid,
@rn := IF (@id = nodoid, @rn + 1,
IF (@id := nodoid, 1, 1)) AS rn
FROM atributo_16
CROSS JOIN (SELECT @rn := 0, @id := -1) AS vars
ORDER BY nodoid, fecha DESC,created_at
) AS t2 ON t1.nodoid = t2.nodoid AND t2.rn = 1
WHERE
nodos.nodotipoid=8;
我已假设nodoid<>-1
,因此使用此值初始化@id
是安全的。
答案 1 :(得分:0)
假设 atributo_16.atributo16id 是主键 - 您可以将相关子选择放入where子句:
SELECT n.nombre, a.super, a.regular, a.diesel
FROM nodos n
LEFT JOIN atributo_16 a USING(nodoid)
WHERE n.nodotipoid = 8
AND (
a.atributo16id = (
SELECT a1.atributo16id
FROM atributo_16 a1
WHERE a1.nodoid = n.nodoid
ORDER BY a1.fecha DESC, a1.created_at
LIMIT 1
)
OR a.nodoid IS NULL -- skip this line if using inner join
)
(nodoid,fecha,created_at)上的索引可以提高性能。
更复杂的解决方案是搜索max(fecha),然后搜索结果min(created_at),然后将结果与最小/最大值上的物理表连接:
SELECT n.nombre, a.super, a.regular, a.diesel
FROM nodos n
LEFT JOIN (
SELECT minc.nodoid, MIN(a.atributo16id) minpk
FROM (
SELECT maxf.nodoid, maxf.maxfecha, MIN(a.created_at) mincreated
FROM (
SELECT a.nodoid, MAX(a.fecha) maxfecha
FROM atributo_16 a
JOIN nodos n USING(nodoid)
WHERE n.nodotipoid = 8
GROUP BY a.nodoid
) maxf
JOIN atributo_16 a
ON a.nodoid = maxf.nodoid
AND a.fecha = maxf.maxfecha
GROUP BY maxf.nodoid, maxf.maxfecha
) minc
JOIN atributo_16 a
ON a.nodoid = minc.nodoid
AND a.fecha = minc.maxfecha
AND a.created_at = minc.mincreated
GROUP BY minc.nodoid, minc.maxfecha, minc.mincreated
) lastreg USING(nodoid)
LEFT JOIN atributo_16 a ON a.atributo16id = lastreg.minpk
WHERE n.nodotipoid = 8
如果没有aproriate指数,这个会很慢。但它的指数很快(nodoid,fecha),并且索引可能会更快(nodoid,fecha,created_at)。
更新:这是另一个简短的解决方案,对您来说可能更直观,因为子选择基于您的原始查询。
SELECT
n.nombre,
a.super AS descuento_navision_super_cif,
a.regular AS descuento_navision_regular_cif,
a.diesel AS descuento_navision_diesel_cif
FROM (
SELECT nodos.nombre,
(SELECT atributo16id FROM atributo_16 WHERE nodoid=nodos.nodoid ORDER BY fecha DESC,created_at LIMIT 1) AS atributo16id
FROM nodos
WHERE nodos.nodotipoid=8
) n
LEFT JOIN atributo_16 a ON a.atributo16id = n.atributo16id