0

我有一个这样的查询 -

    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 中发现我们不能使用这样的集合运算符。

在解释计划中,表 vlaninterfaces 不使用键并扫描所有行。

请通过示例告诉我 NOT IN 的替代方法(如果可能,请使用相同的查询)。

4

2 回答 2

0

您的查询非常复杂,所以我只会展示一部分。可以将 LEFT 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
于 2014-06-30T12:59:36.663 回答
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 查询实际上是丢弃索引。你不需要这样做。

最后,通过 name 和 deviceAlias 的 concat 分组在这里没有任何意义,因为您在 select 中没有任何聚合函数。

于 2014-06-30T13:05:40.110 回答