2016-02-03 14 views
0

У меня есть рабочий стол и связанная с ним рабочая таблица Geofence.optimize IN subquery

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; 

Мне нужно возвращать только рабочие, которые имеют по крайней мере одну запись в таблице workerGeofences с IsActive из 1.

Я смог получить желаемый результат Withe следующее:

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 

, но в подзапросе исчерпывающий, как при выполнении объяснения, я вижу, что он просматривает всю таблицу. Как мне обойти это?

+0

Вы не можете показать нам только половину проблемы. – Strawberry

ответ

1

Прежде всего, ваше объединение неверно! Вы не сравниваете какой-либо общий столбец как на столе, следует добавить, где 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 

И второе, вы ничего из второй таблицы не выбирая, таким образом, соединение является unessesary и в вашем в заявлении, вы не сравниваете правильные идентификаторы, чтобы ваш запрос должен быть:

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 
+0

Используйте EXISTS и отпустите DISTINCT .. или используйте JOIN. – Arth

+0

Я использовал, и я не могу удалить выделение, так как мы не знаем, есть ли дубликаты в его таблице. @Arth – sagi

+0

Предполагая, что каждая рабочая строка уникальна для рабочих (довольно безопасное предположение), вы можете удалить DISTINCT. – Arth

2

Вы на правильном пути, но вам не нужно 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.

+0

(Это лучше, чем принятый ответ, потому что (1) он подчеркивает 'EXISTS', а не медленные' IN' и (2) он упоминает индексы, которые могут помочь.) –

+0

@RickJames , Я поддержал это, но я уже принял другой ответ, прежде чем это было опубликовано. Я уже с успехом использовал индексы и пошел для опции exist в принятом ответе – user2363025

+0

@GordonLinoff один вопрос: есть ли причина, по которой вы проверили isActive <> 0 вместо isActive = 1? Я думал, что проверка <> дороже в запросе? – user2363025

1

Для полноты с помощью 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 
+0

Если для работника имеется несколько строк 'isActive', они будут генерировать повторяющиеся строки. Затем «DISTINCT» запускает, чтобы удалить дубликаты, тем самым делая его менее эффективным, чем решение «EXISTS». –

+0

@ RickJames Да, вы, вероятно, правы .. хотя я думаю, что оптимизатор может привести к тому же запросу. Я включил его больше для полноты, но комментарий будет полезен для путешествующих глаз, – Arth