Использование уникальных индексов с пустыми полями в MySQL? - PullRequest
3 голосов
/ 10 июня 2011

Я могу периодически проверять список пользователей, которые в данный момент находятся в сети. Я хочу превратить это во что-то полезное, например, список записей для каждого пользователя со временем входа / выхода. Нет другого способа определить эту информацию, кроме проверки, кто в данный момент онлайн.
Подумав, я придумал что-то вроде этого:

CREATE TABLE onlineActivity (
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    name CHAR (32) NOT NULL,
    login_time DATETIME NOT NULL,
    logout_time DATETIME NOT NULL,
    time SMALLINT (3) NOT NULL DEFAULT 0,
    online BOOL DEFAULT NULL,
    UNIQUE (name, online),
    PRIMARY KEY (id)
)   ENGINE = MyISAM;

Я запускаю этот запрос каждые несколько минут, чтобы добавить / обновить имена в списке действий:

INSERT INTO onlineActivity (name, login_time, logout_time, online)
    SELECT name, now(), now(), true FROM onlineList ON DUPLICATE KEY UPDATE logout_time = now()

И этот запрос выполняется для каждого пользователя, вышедшего из системы:
(имена определяются путем сравнения двух смежных онлайн-списков, текущего и предыдущего)

UPDATE onlineActivity SET online = NULL WHERE name = ? AND online = 1

Вопросы:

  • Я беспокоюсь о том, что использование поля NULL (online) в индексе UNIQUE - плохая идея и снизит производительность. Я полагаю, что MySQL, возможно, придется выполнить полное сканирование всех online (вместо использования индекса) для каждого имени, чтобы найти имя, отличное от NULL. Может кто-то уточнить, если это так здесь? Я не смог найти никакой информации о том, как MySQL справляется с такой ситуацией.
  • В этом отношении другие системы баз данных (PostgreSQL, SQLite) ведут себя иначе, чем MySQL?
  • Должен ли я вместо первого запроса выполнить два запроса для каждого имени, чтобы проверить, подключен ли в данный момент указанный пользователь, и действовать соответствующим образом?
  • Я думал об этом дизайне, потому что хотел минимизировать количество используемых запросов. Является ли это ошибочной идеей самой по себе?
  • Эта таблица будет получать около 300 ~ 500 тыс. Новых записей в день. Что еще я могу сделать, чтобы уменьшить снижение производительности?

Я хочу сохранить полную историю действий пользователя, а не одну запись.

1 Ответ

1 голос
/ 10 июня 2011

Я не уверен, почему у вас есть уникальное имя и онлайн, поскольку вы пытаетесь создать список онлайн-активности. Ввод уникального ключа, который вы указали, будет означать, что у вас может быть имя только три раза, по одному для каждого состояния (null, true, false).

Что вы фактически делаете, это пытаетесь создать таблицу истории, и в этом случае для использования вашего текущего метода заполнения таблицы вы должны указать уникальный ключ (name, logout_time) с нулевым logout_time, указывающим на текущего вошедшего в систему пользователя поскольку вы хотели бы только одно время выхода из системы, которое будет нулевым).

Примерно так:

CREATE TABLE onlineActivity (
    id INT UNSIGNED NOT NULL AUTO_INCREMENT,
    name CHAR (32) NOT NULL,
    login_time DATETIME NOT NULL,
    logout_time DATETIME NULL,
    time SMALLINT (3) NOT NULL DEFAULT 0,
    online BOOL not null DEFAULT false,
    UNIQUE (name, logout_time),
    PRIMARY KEY (id)
)   ENGINE = MyISAM;

Затем запустите это по расписанию, чтобы обновить таблицу

INSERT IGNORE INTO onlineActivity (name, login_time, logout_time, online)
    SELECT name, now(), null, true FROM onlineList

И это при выходе пользователя из системы

UPDATE onlineActivity SET online = false, logout_time = now() WHERE name = ? AND logout_time = null
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...