Как я могу оптимизировать запрос на обновление SQL с помощью "ГДЕ НЕ ВХОДИТ (... более 1000 наименований ...)"? - PullRequest
0 голосов
/ 18 марта 2020

У меня есть таблица с такими полями: ID, USERNAME, DATA и IS_ONLINE. Каждую минуту я получаю новую большую часть данных с удаленного сервера с текущими пользователями онлайн [(username, is_online, data), ...].

И мне нужно установить IS_ONLINE = 1 только для пользователей в этом массиве, а для других пользователей установить IS_ONLINE = 0. В l oop я делаю запросы UPDATE users SET is_online = 1, data = 'data' WHERE username = 'username'. И затем к набору IS_ONLINE = 0 я выполняю этот запрос:

update users set is_online = 0 where username not in ('user1', 'user2', ... , 'user1000')

И это хорошо работает, если у меня небольшое количество пользователей, но если таблица пользователей содержит более 100 тысяч строк этот запрос выполняется более 50 секунд.

Пожалуйста, вы можете дать мне ответ или идею, как я могу увеличить скорость этого простого запроса.

Спасибо!

1 Ответ

1 голос
/ 22 марта 2020

В настоящее время запрос NOT IN затрагивает все 100 000 строк. Давайте избежим этого, изменив запрос и схему. Вместо того, чтобы устанавливать is_online для всех пользователей, давайте разработаем способ, позволяющий вам касаться только тех, которые в настоящее время онлайн.

Вместо того, чтобы is_online был логическим значением, давайте сделайте это или DATETIME или BIGINT. Затем установите новое, более высокое значение для тех, кто в сети, игнорируя остальные.

Для этого потребуется еще один бит информации - новое высокое значение. Просто сохраните его в другой таблице с одной строкой с одним столбцом.

Эта схема позволяет избежать использования меток времени в комментариях. Единственные пользователи, которые «онлайн», - это пользователи с последним значением в is_online; все остальные находятся в автономном режиме.

Теперь давайте проверим остальную часть схемы. Вы действительно нуждаетесь в id и username? Бросить id и сделать username PRIMARY KEY; это ускорит процесс, потому что не нужно будет выполнять двойной поиск - сначала для поиска идентификатора с учетом имени пользователя, затем для получения строки UPDATE. (Предупреждение: могут быть проблемы, если это FOREIGN KEY из другой таблицы. Если это так, пожалуйста, предоставьте более подробную информацию.)

Другой совет - Использование 1000 операторов для прикосновения к 1000 строкам намного медленнее, чем использование один запрос. Чтобы сделать несколько обновлений различных значений, используйте IODKU.

Я надеюсь, что все это будет сводиться к 3 sql утверждениям:

BEGIN;
$hv = SELECT high_value FROM HighValue FOR UPDATE;
$hv++;
INSERT INTO MainTable
    VALUES
        ('user1', 'blah1', $hv),
        ('user2', 'blah2', $hv),
        ...
    ON DUPLICATE KEY UPDATE 
        data = VALUES(data),   -- sets the new `data` value
        is_online = $hv ;
UPDATE HighValue SET high_value = $hv;
COMMIT;
...