Чат на FB1.5

Запросы, планы, оптимизация запросов, ...

Модераторы: kdv, CyberMax

avenger
Сообщения: 141
Зарегистрирован: 25 окт 2005, 11:53

Чат на FB1.5

Сообщение avenger » 25 окт 2005, 12:05

Здравствуйте уважаемые жители данного форума!

Пишу чат. Как правило в чате 100 человек.

Есть БД со следующей структурой:

Код: Выделить всё

CREATE TABLE MESSAGES (
    MESSAGEID  NUMERIC180 NOT NULL,
    DATETIME   INTEGER NOT NULL,
    USERFK     NUMERIC180 NOT NULL,
    "MESSAGE"  VARCHAR(5000) NOT NULL,
    REPLYMID   NUMERIC180,
    STATUS     SMALLINT NOT NULL
);

CREATE TABLE ONLINE (
    USERFK           NUMERIC180 NOT NULL,
    LASTTIMEREFRESH  INTEGER NOT NULL
);

CREATE TABLE USERS (
    USERID        NUMERIC180 NOT NULL,
);

ALTER TABLE MESSAGES ADD CHECK (STATUS IN (0,1,2));

ALTER TABLE MESSAGES ADD PRIMARY KEY (MESSAGEID);
ALTER TABLE ONLINE ADD PRIMARY KEY (USERFK);
ALTER TABLE USERS ADD PRIMARY KEY (USERID);

ALTER TABLE MESSAGES ADD FOREIGN KEY (USERFK) REFERENCES USERS (USERID) ON DELETE CASCADE;
ALTER TABLE MESSAGES ADD FOREIGN KEY (REPLYMID) REFERENCES MESSAGES (MESSAGEID) ON DELETE CASCADE;
ALTER TABLE ONLINE ADD FOREIGN KEY (USERFK) REFERENCES USERS (USERID) ON DELETE CASCADE;

CREATE INDEX IDX_MESSAGES1 ON MESSAGES (USERFK);
CREATE INDEX IDX_MESSAGES2 ON MESSAGES (REPLYMID);
CREATE UNIQUE INDEX IDX_MESSAGES3 ON MESSAGES (MESSAGEID);
CREATE INDEX IDX_ONLINE1 ON ONLINE (USERFK);
CREATE UNIQUE INDEX IDX_USERS1 ON USERS (USERID);
В основном работа идет с таблицей MESSAGES.

Какие параметры, операции вы посоветуете. Т.е. к примеру надо ли после inserta в таблицу Messages перещитывать статистику для индексов, может есть индексы которые лишние, и.т.д.

Можно ли соптимизировать следующий запрос:

Код: Выделить всё

SELECT U.FIO, U.ISVIP, M.* FROM USERS U, MESSAGES M
                                    WHERE (U.USERID=M.USERFK AND MESSAGEID>$lastmsg)
                                    ORDER BY M.DATETIME
Этот запрос выполняется у пользователя каждые 5 секунд. Если 100 пользователей, то запрос выполнится примерно 100 раз за 5 секунд.

Может быть можно держать часть данных в памяти?

Вообщем нужны советы.
P.S. Пожалуйста отнеситесь к данному вопросу серьезно.

С уважением Иван.

Ivan_Pisarevsky
Заслуженный разработчик
Сообщения: 644
Зарегистрирован: 15 фев 2005, 11:34

Сообщение Ivan_Pisarevsky » 25 окт 2005, 12:11

Этот запрос выполняется у пользователя каждые 5 секунд.
Что мешает пользовать ивенты?
Может быть можно держать часть данных в памяти?
Кеш буфер ФБ+плюс правильное индексирование. Вполне достаточно будет, на мой взгляд.

Ivan_Pisarevsky
Заслуженный разработчик
Сообщения: 644
Зарегистрирован: 15 фев 2005, 11:34

Сообщение Ivan_Pisarevsky » 25 окт 2005, 12:12

Стоп!!!
Это что за нумерик180???
Бр...

avenger
Сообщения: 141
Зарегистрирован: 25 окт 2005, 11:53

Сообщение avenger » 25 окт 2005, 12:13

Что мешает пользовать ивенты?
Что такое ивенты?

avenger
Сообщения: 141
Зарегистрирован: 25 окт 2005, 11:53

Сообщение avenger » 25 окт 2005, 12:14

Ivan_Pisarevsky писал(а):Стоп!!!
Это что за нумерик180???
Бр...
нумерик180 = NUMERIC(18,0)

avenger
Сообщения: 141
Зарегистрирован: 25 окт 2005, 11:53

Сообщение avenger » 25 окт 2005, 12:18

Ivan_Pisarevsky писал(а): Кеш буфер ФБ+плюс правильное индексирование. Вполне достаточно будет, на мой взгляд.
Кеш буфер ФБ можно как нибудь настроить? Может посоветуешь?

Ivan_Pisarevsky
Заслуженный разработчик
Сообщения: 644
Зарегистрирован: 15 фев 2005, 11:34

Сообщение Ivan_Pisarevsky » 25 окт 2005, 12:24

1. ртфм, контескт 'events' www.ibase.ru
2. читаем про скорость обработки integer, int64, numeric... для ключей нафиг не нужен нумерик, обычно интегер 32 бита, если планируется полее 4 миллиардов записей, то пользовать 64 битный ключ.
3. ртфм, контекст 'generator' www.ibase.ru
4. Не стоит называть поле 'DATETIME' или что-то в этом духе, уж больно всякие зарезервированые слова напоминает, а для дат пользовать тип даных timestamp.

avenger
Сообщения: 141
Зарегистрирован: 25 окт 2005, 11:53

Сообщение avenger » 25 окт 2005, 12:32

Ivan_Pisarevsky писал(а):1. ртфм, контескт 'events' www.ibase.ru
2. читаем про скорость обработки integer, int64, numeric... для ключей нафиг не нужен нумерик, обычно интегер 32 бита, если планируется полее 4 миллиардов записей, то пользовать 64 битный ключ.
3. ртфм, контекст 'generator' www.ibase.ru
4. Не стоит называть поле 'DATETIME' или что-то в этом духе, уж больно всякие зарезервированые слова напоминает, а для дат пользовать тип даных timestamp.
Насчет Numeric и integer ясно.

У меня есть 2-а генератора(users, messages) и соответственно при инсерте в таблицу срабатывает событие. А для чего еще ты предлагаешь использовать события?


Обновление статистики нужно после каждого inserta или раз в 100 инсертов например ?

Код: Выделить всё

SET STATISTICS INDEX RDB$PRIMARY4

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 25 окт 2005, 12:37

да не нужно обновление статистики. ты еще запросы не написал, а уже о статистике по индексам бепокоишься? :-)

Тем более, что слышал звон, и не знаешь где он - по первичным ключам обновлять статистику не имеет смысла. потому что они УНИКАЛЬНЫЕ. Статистику, обычно, если и обновляют, то по неуникальным индексам.
Скачай IBAnalyst, он тебе скажет, когда ее обновить, и даже даст по правой кнопке одним нажатием это сделать.

avenger
Сообщения: 141
Зарегистрирован: 25 окт 2005, 11:53

Сообщение avenger » 25 окт 2005, 12:43

kdv писал(а): ты еще запросы не написал
Запросы написаны:


Когда пользователь написал сообщение:

Код: Выделить всё

             $db->Execute("INSERT INTO MESSAGES (DATETIME, USERFK, "MESSAGE", REPLYMID, STATUS)
                           VALUES ($addtime, $UserID,    '$Message', $ReplyMID, $Status)") or Halt($db->ErrorMsg());
И при рефреше каждые 5-ть сек:

Код: Выделить всё

            $rs = $db->SelectLimit("SELECT U.FIO, U.ISVIP, M.* FROM USERS U, MESSAGES M
                                    WHERE (U.USERID=M.USERFK AND MESSAGEID>$lastmsg)
                                    ORDER BY M.DATETIME", $confv["messageCount_refresh"], -1) or Halt($db->ErrorMsg());

и

Код: Выделить всё

                  $reply = $db->GetRow("SELECT U.FIO, M.* FROM USERS U, MESSAGES M
                                        WHERE (U.USERID=M.USERFK AND M.MESSAGEID=".$newmsg[$name]['replymid'].")") or Halt($db->ErrorMsg());


Ivan_Pisarevsky
Заслуженный разработчик
Сообщения: 644
Зарегистрирован: 15 фев 2005, 11:34

Сообщение Ivan_Pisarevsky » 25 окт 2005, 13:27

У меня есть 2-а генератора(users, messages) и соответственно при инсерте в таблицу срабатывает событие. А для чего еще ты предлагаешь использовать события?
Это видимо(поглядемши в потолок :roll: ) срабатывает таки триггер на втсавку, а не генерируется ивент. А ивенты вместо того чтоб сервер не долбать каждые 5 секунд новым селектом.

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Сообщение Dimitry Sibiryakov » 25 окт 2005, 13:28

CREATE INDEX IDX_MESSAGES1 ON MESSAGES (USERFK);
CREATE INDEX IDX_MESSAGES2 ON MESSAGES (REPLYMID);
CREATE UNIQUE INDEX IDX_MESSAGES3 ON MESSAGES (MESSAGEID);
CREATE INDEX IDX_ONLINE1 ON ONLINE (USERFK);
CREATE UNIQUE INDEX IDX_USERS1 ON USERS (USERID);
Эти индексы убить сразу и насмерть. Для PK и FK индексы создаются автоматически и твои будут только вводить оптимизатор в заблуждение.

avenger
Сообщения: 141
Зарегистрирован: 25 окт 2005, 11:53

Сообщение avenger » 25 окт 2005, 14:12

Структура приняла next вид:

Код: Выделить всё

CREATE GENERATOR MESSAGEID;
CREATE GENERATOR USERID;

CREATE TABLE MESSAGES (
    MESSAGEID  INTEGER NOT NULL,
    DATETIME   INTEGER NOT NULL,
    USERFK     INTEGER NOT NULL,
    "MESSAGE"  VARCHAR(5000) NOT NULL,
    REPLYMID   INTEGER,
    STATUS     SMALLINT NOT NULL
);


CREATE TABLE ONLINE (
    USERFK           INTEGER NOT NULL,
    LASTTIMEREFRESH  INTEGER NOT NULL
);


CREATE TABLE USERS (
    USERID        INTEGER NOT NULL,
    LOGIN         VARCHAR(40) NOT NULL,
    "PASSWORD"    VARCHAR(40),
    FIO           VARCHAR(200) NOT NULL,
    AREA          VARCHAR(200),
    ORGANIZATION  VARCHAR(200),
    ISVIP         SMALLINT NOT NULL,
    ISINFOUPDATE  SMALLINT NOT NULL,
    ISACTIVE      SMALLINT NOT NULL
);

ALTER TABLE MESSAGES ADD CHECK (STATUS IN (0,1,2));
ALTER TABLE USERS ADD CHECK (ISVIP IN (0,1));
ALTER TABLE USERS ADD CHECK (ISINFOUPDATE IN (0,1));
ALTER TABLE USERS ADD CHECK (ISACTIVE IN (0,1));

ALTER TABLE USERS ADD UNIQUE (LOGIN);

ALTER TABLE MESSAGES ADD PRIMARY KEY (MESSAGEID);
ALTER TABLE ONLINE ADD PRIMARY KEY (USERFK);
ALTER TABLE USERS ADD PRIMARY KEY (USERID);

ALTER TABLE MESSAGES ADD FOREIGN KEY (USERFK) REFERENCES USERS (USERID) ON DELETE CASCADE;
ALTER TABLE MESSAGES ADD FOREIGN KEY (REPLYMID) REFERENCES MESSAGES (MESSAGEID) ON DELETE CASCADE;
ALTER TABLE ONLINE ADD FOREIGN KEY (USERFK) REFERENCES USERS (USERID) ON DELETE CASCADE;
Можно поподробнее об ивентах?

avenger
Сообщения: 141
Зарегистрирован: 25 окт 2005, 11:53

Сообщение avenger » 25 окт 2005, 14:15

Ivan_Pisarevsky писал(а):Это видимо(поглядемши в потолок :roll: ) срабатывает таки триггер на втсавку, а не генерируется ивент. А ивенты вместо того чтоб сервер не долбать каждые 5 секунд новым селектом.
Наверно стоит уточнить: чат пишется на php. Ивенты соответственно не
могу обрабатывать.

Может есть советы по оптимизации настроек fb в fb.conf. Т.е. предложения по настройке кэша,...

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 25 окт 2005, 14:41

эх... alter table при добавлении PK/FK/UNIQUE пишется например так:

alter table add CONSTRAINT FK_TABLE1 foreign key (field) references (pkfield).

потому что если тебе вдруг понадобится изменить или удалить этот FK, ты сделаешь просто
alter table drop constraint CONSTRAINT_NAME.
В противном случае тебе придется шарить по системным таблицам, в поисках автоматически созданных имен constraint типа INTEG10, INTEG11 и т.п.

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

avenger
Сообщения: 141
Зарегистрирован: 25 окт 2005, 11:53

Сообщение avenger » 25 окт 2005, 15:02

Первая загрузка модуля Refresh делает запросы:

Код: Выделить всё

--------------------------------------------------------------------------------
(firebird): SELECT ISACTIVE FROM USERS WHERE USERID=177   
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
(firebird): UPDATE ONLINE SET LASTTIMEREFRESH=1130237695 WHERE USERFK=177   
--------------------------------------------------------------------------------
(firebird): SELECT USERFK FROM ONLINE   
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
(firebird): SELECT USERID, FIO, AREA, ORGANIZATION, ISVIP FROM USERS WHERE USERID IN (177)   
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
(firebird): SELECT USERFK FROM ONLINE WHERE LASTTIMEREFRESH < 1130237635   
--------------------------------------------------------------------------------
(firebird): SELECT MAX(MESSAGEID) FROM MESSAGES   
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
(firebird): SELECT FIRST 20 U.FIO, U.ISVIP, M.* FROM USERS U, MESSAGES M WHERE (U.USERID=M.USERFK AND MESSAGEID>12) ORDER BY M.DATETIME   
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
(firebird): SELECT U.FIO, M.* FROM USERS U, MESSAGES M WHERE (U.USERID=M.USERFK AND M.MESSAGEID=6)   
--------------------------------------------------------------------------------


--------------------------------------------------------------------------------
(firebird): SELECT U.FIO, M.* FROM USERS U, MESSAGES M WHERE (U.USERID=M.USERFK AND M.MESSAGEID=5)   
--------------------------------------------------------------------------------

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 25 окт 2005, 15:10

ты к чему это все шлешь? чтобы тебе сказали, хорошие запросы или плохие? ну, нормальные запросы....

avenger
Сообщения: 141
Зарегистрирован: 25 окт 2005, 11:53

Сообщение avenger » 25 окт 2005, 15:15

kdv писал(а):ты к чему это все шлешь? чтобы тебе сказали, хорошие запросы или плохие? ну, нормальные запросы....
Вот это смущает:

Код: Выделить всё

SELECT USERID, FIO, AREA, ORGANIZATION, ISVIP FROM USERS WHERE USERID IN (177)
Как лучше сделать если в in скажем 20 значений: 20 select-ов соответственно или один но с in-ом?

avenger
Сообщения: 141
Зарегистрирован: 25 окт 2005, 11:53

Сообщение avenger » 25 окт 2005, 15:21

Всем огромное спасибо!!!!!!!!!! Но хотелось напоследок услышать совет по настройке кэширования в FB1.5 for winnt2000.

Что за параметры DefaultDbCachePages, SortMemBlockSize и стоит вообще их менять?

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Сообщение kdv » 25 окт 2005, 17:38

там же рядом с параметрами написано, зачем они и чего в них писать.

Ответить