优化 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
我有一个 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