如何在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