优化 IN 子查询

optimise IN subquery

我有一个 worker table 和一个关联的 workerGeofence table。

CREATE TABLE IF NOT EXISTS `workergeofences` (
`ID` int(11) NOT NULL,
  `WorkerID` varchar(20) NOT NULL,
  `GeofenceID` int(11) NOT NULL,
  `isActive` tinyint(4) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=107 DEFAULT CHARSET=latin1;

我只需要 return 在 workerGeofences table 中至少有一个条目且 isActive 为 1 的工人。

我能够通过以下方式获得想要的结果:

    SELECT distinct w.ID, Title, FName, SName, Email, Birthday, Address, Phone, description,
 companyID 
FROM Workers w WHERE companyID = ? 
and w.ID IN (SELECT WorkerID FROM WorkerGeofences WHERE isActive <> 0)
    limit ?,10

但是 in 子查询是详尽无遗的,因为当我 运行 解释时,我可以看到它正在扫描整个 table。我该如何解决这个问题?

首先,你的加入是错误的!您没有比较 table 上的任何公共列,您应该像这样在 workerGeofences.workerID = w.id 处添加:

SELECT  w.ID, Title, FName, SName, Email, Birthday, Address, Phone,
        description, companyID
    FROM  Workers w
    join  workerGeofences
    WHERE  workerGeofences.workerID = w.ID companyID = ?
      and  w.ID IN (
        SELECT  WorkerID
            FROM  WorkerGeofences s
            WHERE  isActive <> 0
              and  s.workerID = w.id
                   )
    limit  0,10 

其次,您没有从第二个 table 中选择任何内容,因此连接是不必要的,并且在您的 IN 语句中,您没有比较正确的 ID,因此您的查询应该是:

SELECT  w.ID, Title, FName, SName, Email, Birthday, Address, Phone,
        description, companyID
    FROM  Workers w
    WHERE  companyID = ?
      and  w.ID IN (
        SELECT  WorkerID
            FROM  WorkerGeofences s
            WHERE  isActive <> 0
              and  s.workerID = w.ID
                   )
    limit  0,10 

此外,您可以为此使用 EXISTS()。

SELECT  w.ID, Title, FName, SName, Email, Birthday, Address, Phone,
        description, companyID
    FROM  Workers w
    WHERE  companyID = ?
      and  exists 
      ( SELECT  1
            FROM  WorkerGeofences s
            WHERE  isActive = 1
              and  s.workerID = w.ID
      )
    limit  0,10

你走在正确的轨道上,但你不应该需要 select distinct。这会减慢查询速度,除非您知道存在重复项——这不太可能,因为您选择的是 WOrkers.Id.

SELECT w.* 
FROM Workers w 
WHERE w.companyID = ? AND
      EXISTS (SELECT 1
              FROM workerGeofences wg
              WHERE w.ID = wg.WorkerID AND wg.isActive <> 0
             )
LIMIT ?, 10;

然后,对于此查询,您需要 Workers(CompanyId, Id)workerGeofences(WorkerId, isActive) 上的索引。

注意:为了方便,我只是输入了 select *。我假设所有列都来自 Workers table.

为了完整性,使用 JOIN:

SELECT DISTINCT w.ID,
       w.Title, 
       w.FName, 
       w.SName, 
       w.Email, 
       w.Birthday, 
       w.Address, 
       w.Phone, 
       w.description, 
       w.companyID
  FROM Workers w 
  JOIN WorkerGeofences wg
    ON wg.workerID = w.id
   AND wg.isActive = 1
 WHERE w.companyID = ? 
 LIMIT ?,10