我有这样的查询 -
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) ;
我尝试使用MINUS但是在mysql中发现我们不能使用这样的set运算符。
在Explain plan中,表vlaninterfaces不使用键并扫描所有行。
请让我知道NOT IN的替代示例(如果可能的话,同样的查询)。
答案 0 :(得分:0)
您的查询非常复杂,所以我只展示部分内容。可以将JOFT JOIN挂到表上并检查null而不是使用NOT IN。即如果我们有查询:
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上的连接更改为显式 - 我发现这更具可读性):
SELECT
CONCAT(u.name, u.deviceAlias),
u.name,
u.deviceAlias,
j.description,
u.description AS vlanDescription
FROM
vlaninterfaces u
INNER JOIN interfacedescriptioninfo j ON (u.interfacedescriptioninfoid = j.id AND u.deviceId = j.deviceId AND u.interfaceNameAlias = j.name )
LEFT JOIN devices da ON (j.toDevice = da.deviceAlias AND da.siteId = 12)
WHERE
da.deviceAlias IS NULL
答案 1 :(得分:0)
好的,这需要大量的试验和错误,但我总是尝试将IN子句重写为连接,从而避免使用隐式子查询。同样适用于NOT IN,你可以用LEFT JOIN + WHERE替换为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 of name和deviceAlias进行分组在这里没有意义,因为你在select中没有任何聚合函数。