如何在mysql中优化此查询?
我有一个这样的问题-如何在mysql中优化此查询?,mysql,sql,performance,optimization,notin,Mysql,Sql,Performance,Optimization,Notin,我有一个这样的问题- SELECT CONCAT(u.name, u.deviceAlias), u.name, u.deviceAlias, j.description, u.description AS vlanDescription FROM vlaninterfaces u, interfacedescriptioninfo j WHERE u.interfacedescriptioninfoid = j.id AND u.deviceId
SELECT
CONCAT(u.name, u.deviceAlias),
u.name,
u.deviceAlias,
j.description,
u.description AS vlanDescription
FROM
vlaninterfaces u,
interfacedescriptioninfo j
WHERE u.interfacedescriptioninfoid = j.id
AND u.deviceId = j.deviceId
AND u.interfaceNameAlias = j.name
AND j.toDevice NOT IN
(SELECT
deviceAlias
FROM
devices
WHERE siteId = 12)
AND u.deviceAlias IN
(SELECT
deviceAlias
FROM
devices
WHERE siteId = 12)
AND CONCAT(u.name, u.deviceAlias) NOT IN
(SELECT DISTINCT
CONCAT(v.name, fromDevice)
FROM
vlaninterfaces v,
interfacedescriptioninfo i
WHERE v.interfacedescriptioninfoid = i.id
AND v.deviceId = i.deviceId
AND v.interfacenameAlias = i.name
AND v.deviceAlias IN
(SELECT
deviceAlias
FROM
devices
WHERE siteId = 12)
AND v.interfacenameAlias LIKE '%ae%'
AND IF(
i.toDevice IS NULL,
i.interconnectedDevice,
i.toDevice
) IN
(SELECT
deviceAlias
FROM
devices
WHERE deviceClass = 'SWITCH'
AND siteId = 12))
GROUP BY CONCAT(u.name, u.deviceAlias) ;
我尝试使用减号,但在mysql中发现我们不能使用这样的集合运算符
在Explain plan中,表VLAN不使用键并扫描所有行
请让我知道不在示例中的替代选项(如果可能,请使用相同的查询)。您的查询非常复杂,因此我仅显示部分。可以左键联接到表并检查null,而不是使用notin。即,如果我们有疑问:
SELECT
CONCAT(u.name, u.deviceAlias),
u.name,
u.deviceAlias,
j.description,
u.description AS vlanDescription
FROM
vlaninterfaces u,
interfacedescriptioninfo j
WHERE u.interfacedescriptioninfoid = j.id
AND u.deviceId = j.deviceId
AND u.interfaceNameAlias = j.name
AND j.toDevice NOT IN
(SELECT
deviceAlias
FROM
devices
WHERE siteId = 12)
然后,我们可以使用siteId 12连接到设备别名,并在where子句中检查连接是否成功(注意,在下面的示例中,我还将vlaninterfaces和interfacedescriptioninfo上的连接更改为显式连接-我发现这更具可读性):
好的,这将需要大量的尝试和错误,但我总是尝试将IN子句重写为联接,从而避免隐式子查询。NOT IN的情况也是如此,您可以将其替换为左JOIN+,其中某些内容为NULL
SELECT
CONCAT(u.name, u.deviceAlias),
u.name,
u.deviceAlias,
j.description,
u.description AS vlanDescription
FROM
vlaninterfaces u
JOIN interfacedescriptioninfo j ON u.interfacedescriptioninfoid = j.id AND u.deviceId = j.deviceId AND u.interfaceNameAlias = j.name
JOIN devices d2 ON d2.deviceAlias=u.deviceAlias AND d2.siteId=12
LEFT JOIN devices d1 ON d1.deviceAlias=j.toDevice AND d1.siteId = 12
LEFT JOIN (SELECT DISTINCT v.name, fromDevice
FROM
vlaninterfaces v,
JOIN interfacedescriptioninfo i ON v.interfacedescriptioninfoid = i.id AND v.deviceId = i.deviceId AND v.interfacenameAlias = i.name
JOIN devices d3 ON d3.deviceAlias=v.deviceAlias AND d3.siteId=12
JOIN devices d4 ON d4.deviceAlias=IF(i.toDevice IS NULL, i.interconnectedDevice, i.toDevice) AND d4.siteId=12 AND d4.deviceClass = 'SWITCH'
WHERE v.interfacenameAlias LIKE '%ae%'
) as subquery ON u.name=subquery.name AND u.deviceAlias=subquery.fromDevice
WHERE d1.deviceAlias is NULL -- this replaces the first NOT IN
and subquery.name is NULL -- this replaces the second NOT IN
通过两个字段的concat进行查询实际上是丢弃索引。你不需要那样做
最后,按concat对name和deviceAlias进行分组在这里没有任何意义,因为在select中没有任何聚合函数
SELECT
CONCAT(u.name, u.deviceAlias),
u.name,
u.deviceAlias,
j.description,
u.description AS vlanDescription
FROM
vlaninterfaces u
JOIN interfacedescriptioninfo j ON u.interfacedescriptioninfoid = j.id AND u.deviceId = j.deviceId AND u.interfaceNameAlias = j.name
JOIN devices d2 ON d2.deviceAlias=u.deviceAlias AND d2.siteId=12
LEFT JOIN devices d1 ON d1.deviceAlias=j.toDevice AND d1.siteId = 12
LEFT JOIN (SELECT DISTINCT v.name, fromDevice
FROM
vlaninterfaces v,
JOIN interfacedescriptioninfo i ON v.interfacedescriptioninfoid = i.id AND v.deviceId = i.deviceId AND v.interfacenameAlias = i.name
JOIN devices d3 ON d3.deviceAlias=v.deviceAlias AND d3.siteId=12
JOIN devices d4 ON d4.deviceAlias=IF(i.toDevice IS NULL, i.interconnectedDevice, i.toDevice) AND d4.siteId=12 AND d4.deviceClass = 'SWITCH'
WHERE v.interfacenameAlias LIKE '%ae%'
) as subquery ON u.name=subquery.name AND u.deviceAlias=subquery.fromDevice
WHERE d1.deviceAlias is NULL -- this replaces the first NOT IN
and subquery.name is NULL -- this replaces the second NOT IN