Запрос к базе с страницы чата php

Статус
Закрыто для дальнейших ответов.

FiRеFоX

V.I.P.
Регистрация
07.08.2010
Сообщения
744
Таблица chat:
Код:
CREATE TABLE  `chat` (
`id` MEDIUMINT( 9 ) NOT NULL AUTO_INCREMENT ,
`id_room` TINYINT( 4 ) NOT NULL ,
`id_login` MEDIUMINT( 9 ) NOT NULL ,
`id_login_from` MEDIUMINT( 9 ) NOT NULL ,
`privat` TINYINT( 4 ) NOT NULL ,
`text` CHAR( 255 ) NOT NULL ,
`data` INT( 11 ) NOT NULL ,
PRIMARY KEY (  `id` ) ,
KEY  `data` (  `data` ) ,
KEY  `id_room` (  `id_room` )
) ENGINE = MYISAM DEFAULT CHARSET = utf8;
Собственно поля:
id_room - номер комнаты чата от 1 до 5
id_login - id юзера из основной таблицы (это автор поста)
id_login_from - id юзера из основной таблицы (кому адресовано сообщение), если никому, то 0
privat - 1 - написано приватно какому-то игроку, чтобы никто не видел, 0 - в общий чат

Такой вот запрос получается:
Код:
SELECT
`chat`.`id` as `id_post`, `user`.`login`, `user`.`data_color_nick`, `user`.`id_color_nick`, `chat`.`id_login`, `chat`.`text`, `chat`.`privat`, `chat`.`id_login_from`, `otvet`.`login` as `login_komu`, `chat`.`data`
FROM `chat`
LEFT JOIN `user` ON `chat`.`id_login` = `user`.`id`
LEFT JOIN `user` as `otvet` ON `chat`.`id_login_from` = `otvet`.`id`
WHERE `chat`.`id_room` = 1 AND (`chat`.`id_login` = 1 OR `chat`.`privat` = 0 OR `chat`.`id_login_from` = 1)
ORDER BY `chat`.`id` DESC LIMIT 0, 15
Запрос выбирает посты из комнаты 1 и показывает приватные сообщения юзеру 1, а также сообщения в общую комнату. Последние.
При ~400.000 строк запрос выполняется ~ 1.5сек - 2сек. Вобщем очень долго. Если убрать order by, то ещё более менее нормально.
Может что-то нужно переделать, изменить? Подскажите)
 

lekzd

parse error: parse error, unexpected T_STRING...
Регистрация
17.02.2011
Сообщения
1 125
[member=FiRеFоX], надо убрать подзапросы
Код:
LEFT JOIN `user` ON `chat`.`id_login` = `user`.`id`
LEFT JOIN `user` as `otvet` ON `chat`.`id_login_from` = `otvet`.`id`
сомневаюсь, что для каждого сообщения надо брать инфу для текущего юзера, цвет его ника и т.п. - эту инфу можно взять 1 раз
 

FiRеFоX

V.I.P.
Регистрация
07.08.2010
Сообщения
744
[member=FiRеFоX], надо убрать подзапросы
Код:
LEFT JOIN `user` ON `chat`.`id_login` = `user`.`id`
LEFT JOIN `user` as `otvet` ON `chat`.`id_login_from` = `otvet`.`id`
сомневаюсь, что для каждого сообщения надо брать инфу для текущего юзера, цвет его ника и т.п. - эту инфу можно взять 1 раз
Каким образом? Раскройте секрет
 

lekzd

parse error: parse error, unexpected T_STRING...
Регистрация
17.02.2011
Сообщения
1 125
Каким образом? Раскройте секрет
Какой секрет?
у каждого материала в таблице в БД должен быть свой ID, запросить массив с нужными пользователями, приписать их к ID в массив, а при выводе чата дергать из БД только ID юзеров и подставлять нужные значения, зачем для каждого сообщения каждый раз брать ник пользователя?
 

AngelGabriel

И имя мне - легион
Регистрация
23.11.2008
Сообщения
778
джоины это вобще адъ и Израиль, может слегка денормализовать так сказать и прикрути мемкешку.
Как сказал бы товарищ Сталин: It's not good. InnoDB - наше все. май исам лочит таблицу при инсерте. Хотя исам быстрей селектится, но так как в таблицу чата больше наверное инсертится то лучше инноДБ.
 

lekzd

parse error: parse error, unexpected T_STRING...
Регистрация
17.02.2011
Сообщения
1 125
Как сказал бы товарищ Сталин: It's not good. InnoDB - наше все.
Видно ваш "Сталин" уходя расстрелял все поколение старых проггеров, потому нынче модно закидывать любые нагрузки "железом". оптимизация, только оптимизация =)
 

AngelGabriel

И имя мне - легион
Регистрация
23.11.2008
Сообщения
778
Причем тут "закидывание железом" (дежавю, в подкасте слышал то же)? Где я написал, добавь озу или проц получше?
 

CamaroSS

Well-Known Member
Регистрация
21.02.2012
Сообщения
176
InnoDB/XtraDB при куче вставок-выборок - это норма, я щитаю. Плюс надёжность опять же
Хотя исам быстрей селектится
Я попрошу не путать ISAM с MyISAM)) И насчёт скорости селекта вопрос очень спорный.
 

AngelGabriel

И имя мне - легион
Регистрация
23.11.2008
Сообщения
778
Просто My не дописал, думал из контекста понятно.
 

FiRеFоX

V.I.P.
Регистрация
07.08.2010
Сообщения
744
у каждого материала в таблице в БД должен быть свой ID, запросить массив с нужными пользователями, приписать их к ID в массив, а при выводе чата дергать из БД только ID юзеров и подставлять нужные значения, зачем для каждого сообщения каждый раз брать ник пользователя?
Честно говоря, я нифига не понял хода мысли.. Можно пример кода в короткометражке по данному примеру чата?
 

lekzd

parse error: parse error, unexpected T_STRING...
Регистрация
17.02.2011
Сообщения
1 125
Честно говоря, я нифига не понял хода мысли.. Можно пример кода в короткометражке по данному примеру чата?
запросить список юзеров из таблицы, это понятно?

поместить результаты в массив с ключами = ID юзеров? это ясно?

запросить нужные сообщения из БД без сторонних подзапросов, это думаю тоже ясно

далее, при выводе, обращаться к таблице с юзерами по ID из полей "id_login" и "id_login_from", чтобы получать нужные значения
 

FiRеFоX

V.I.P.
Регистрация
07.08.2010
Сообщения
744
запросить список юзеров из таблицы, это понятно?
При добавлении сообщения? Да, понятно.
поместить результаты в массив с ключами = ID юзеров? это ясно?
Дополнительная таблица, в которой будет храниться инфа о юзерах или эта таблица же с сообщениями, но сделать доп.поле?
запросить нужные сообщения из БД без сторонних подзапросов, это думаю тоже ясно
Да, ясно.
далее, при выводе, обращаться к таблице с юзерами по ID из полей "id_login" и "id_login_from", чтобы получать нужные значения
При выводе? Так это тогда по 2 запроса на каждое сообщение для id_login и id_login_from.. А если на странице 20 сообщений от разных игроков, то это 40 запросов..
А если сохранять цвет ника и логин всё в одной таблице и делать просто select без соединения, то при изменении логина или цвета в чате юзером, то все старые сообщения будут с старым логином или цветом ника..
Так?
 

brevis

Well-Known Member
Регистрация
10.08.2010
Сообщения
452
Попробуй добавить дополнительное условие в тех местах, где не нужно выводить вообще все сообщения чата, а скажем только за последние полчаса:
Код:
WHERE `chat`.`data` > time() - 30_минут
Идея в том, что бы как-то сократить набор данных. У меня в некоторых случаях скорость выборки увеличивается намного, иногда даже такое бывает:
Код:
без WHERE: Запрос занял 6.5316 сек.
c WHERE: Запрос занял 0.1533 сек.
 

FiRеFоX

V.I.P.
Регистрация
07.08.2010
Сообщения
744
Попробуй добавить дополнительное условие в тех местах, где не нужно выводить вообще все сообщения чата, а скажем только за последние полчаса:
Вооот! Уже что-то!
И как написали выше также сменил с myisam на iinodb таблицу и тоже скорость улучшилась.
 

CamaroSS

Well-Known Member
Регистрация
21.02.2012
Сообщения
176
По-моему, инфу о активных юзерах можно просто запрашивать раз секунд в 10 и полученную инфу складывать в какой-нибудь массив на клиенте, и оттуда доставать, если требуется.
 

FiRеFоX

V.I.P.
Регистрация
07.08.2010
Сообщения
744
Ну если уж на то пошло, то тогда лучше создать таблицу MEMORY и хранить там в оперативке около 1000 последних сообщений и выводить оттуда.. И периодично сохранять в основную таблицу сообщения юзеров в основную.. Чем делать отдельный массив)
 

mrlasking

$_GET['rich'] or die('trying');
Регистрация
22.05.2012
Сообщения
323
Фокс, готовься к покупке кучи железа. Или запомни: "чаты на php - адовое зло". Удели 1 день этому вопросу, но подними ноду (node.js) и пиши чат хотя бы на нем. Нагрузка на сервак упадет в сотни раз. Без шуток, на опыте проверено. Еще лучше, конечно, написать функционал чата на c/c++ и тогда его уже можно спаривать с php. Но node все равно намного шустрее и меньше ресурсов жрет.
 
Статус
Закрыто для дальнейших ответов.
Верх Низ