Вот кусок кода из user_block
отвечающий за составления списка пользователей онлайн.
// Perform database queries to gather online user lists. We use s.timestamp
// rather than u.access because it is much faster.
$anonymous_count = sess_count($interval);
$authenticated_users = db_query('SELECT DISTINCT u.uid, u.name, s.timestamp FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.timestamp >= %d AND s.uid > 0 ORDER BY s.timestamp DESC', $interval);
Смотрим на запрос и думаем - а какого Художника был просто не сделан запрос к таблице users с условием по полю acceess
обращаем внимание на комментарий выше, где нам пытаются обьяснить:
мол использование индекса из таблицы session это значительно быстрее чем использование чистой таблицы users и поля access
Мы не поверим автору и загляним в EXPLAIN
вводные
таблица SESSION 37МБ
таблица users 103МБ
О ЧУДО
Автор этого запроса явно МНОГО КУРИЛ БАМБУКА а не православного канабиса.
даже невооруженным глазом видно, что использование таблицы session не просто МАРАЗМ а еще и КРАЙНЕ ВРЕДНЫЙ МАРАЗМ
о чем ВОПИТ Using where; Using temporary; Using filesort
Попробуем все таки понять как ТАКОЕ могло попасть в ядро
Когда, автор проводил свои исследования, он
а) сидел практически с пустой таблицой session
б) даже не удосужился посмотреть EXPLAIN обоих запросов.
ошибка в общем то не критичная, в случае если есть и правильно работает кеширование mysql (возможна схожая ситуация и на других БД)
разница на обоих запросах
на оригинальном варианте 0.017 Ms
на правильном 0.005 Ms
если же кеширования НЕТ то оригинальный запрос может выполняться ощутимо дольше.
из за необходимости создания временной таблицы и файловых операций.
UPD: Как справедливо заметил
А как иначе вывести, что под одним логином несколько человек на сайте?
мой запрос с этим не справится.
В случае если такой функционал необходим, то модифицируем оригинальный запрос таким образом, чтобы избавится от файлсорта и временных таблиц убирая из запроса
не нужный в данном случае DISTINCT и ORDER by
саму сортировку выполнить средствами php по полю timestamp после того как составлен результирующий массив, или в момент его составления.
SELECT u.uid, u.name, s.timestamp FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.timestamp >= %d AND s.uid > 0
Вложение | Размер |
---|---|
7may.jpg | 104.3 КБ |
Комментарии
А что если пользователь разлогинился? Второй запрос в этом случае будет выдавать некорректное значение.
А как иначе вывести, что под одним логином несколько человек на сайте?
PS: кстати идея хорошая - можно сделать настройку для блока - выводить или нет сессии под одним логином.
Ромка, если человек разлогинился то никак (с такой оптимизацией)
Но погонять explain и достроить какой-нить индекс можно... я что-то когда-то ваял по этому поводу...
добавить второе граничное условие. Больше такого но меньше такого - считать что пользователь онлайн. (например 1 минута плюс минус.)
Это конечно не вполне точно, но допустимо, в силу того что далеко не все разлогиниваются а следовательно и оригинальный запрос выдает таких пользователей как онлайн.
Угу. В моем случае никак.
Но даже если брать это во внимание то запрос написан через жопу.
Правильно было бы делать тогда так:
SELECT u.uid, u.name, s.timestamp FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.timestamp >= %d AND s.uid > 0
Убран ненужный в данном случае DISTINCT и ORDER использование которых и приводит к появлению файлсорта с временной таблицей.
Сортировку потом сделать средствами php.
UPD: в догонку.
Только сейчас обратил внимание что оригинальный запрос так же содержит и ошибку, в случае если два человека под одним логином присутствуют на сайте, и в таблице session они окажутся с одинаковым timestamp их посчитают за одного.