У меня есть база данных с примерно 50 миллионами записей, показывающих состояние устройства на данный день, упрощенное до формы:

 id | status
-------------
1   | Off
1   | Off
1   | On
2   | Off
2   | Off
3   | Off
3   | Off
3   | On
...

Таким образом, что каждый идентификатор гарантированно будет иметь как минимум 2 строки со статусом «выключено», но не обязательно должен иметь статус «включено». Я пытаюсь получить список только идентификаторов, у которых нет статуса «Вкл.». Например, в приведенном выше наборе данных я бы хотел, чтобы запрос возвращался только с '2'

Текущий запрос:

SELECT DISTINCT id FROM table 

EXCEPT

SELECT DISTINCT id FROM table WHERE status <> 'Off'

Кажется, что это работает, но ему приходится дважды перебирать всю таблицу, что в итоге занимает ~ 10-12 минут для выполнения каждого запроса. Есть ли более простой способ сделать это с помощью всего одного запроса?

sql
0
D. Stewart 8 Сен 2016 в 21:27

3 ответа

Лучший ответ

Вместо этого вы можете использовать WHERE NOT EXISTS:

Select Distinct Id
From   Table  A
Where Not Exists
(
    Select  *
    From    Table  B
    Where   A.Id = B.Id
    And     B.Status = 'On'
)

Я также рекомендовал бы посмотреть индексы в столбце Status. 10-12 минут для бега - это слишком много. Даже с 50 миллионами записей при правильной индексации такой запрос не должен занимать больше секунды.

Чтобы добавить индекс в столбец, вы можете запустить это (я предполагаю, что SQL Server, ваш синтаксис может отличаться):

Create NonClustered Index Ix_YourTable_Status On YourTable (Status Asc);
3
Siyual 8 Сен 2016 в 18:36

Вы можете использовать условное агрегирование.

select id
from table 
group by id
having count(case when status='On' then 1 end)=0
1
Vamsi Prabhala 8 Сен 2016 в 18:30

Вы можете использовать САМОСОЕДИНЕНИЕ ..

         SELECT DISTINCT  A.Id
         FROM Table  A
             LEFT JOIN Table B ON A.Id=B.Id
         WHERE B.Status='On' 
                   AND B.Id IS NULL 
0
Unnikrishnan R 8 Сен 2016 в 18:52