Цель: Предложить объекты по выбору пользователя
Данные: Таблица, содержащая информацию о том, как пользователи будут упорядочивать подмножество объектов от худшего к лучшему; Пример:
1 2 3 4 5 6
John: A B G J S O
Mary: A C G L
Joan: B C L J K
Stan: G J C L
В 20 раз больше пользователей, чем объектов, в линейке каждого пользователя содержится 50-200 объектов.
Таблица:
CREATE TABLE IF NOT EXISTS `pref` (
`usr` int(10) unsigned NOT NULL,
`obj` int(10) unsigned NOT NULL,
`ord` int(10) unsigned NOT NULL,
UNIQUE KEY `u_o` (`usr`,`obj`),
KEY `u` (`usr`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Основная идея: Итерация в объектах пользователя, начиная со второго худшего, построение пар (A> B); ищите их в очередях других пользователей и перечисляйте элементы лучше, чем А. в соответствии с этими пользователями.
Запрос:
SELECT e.obj, COUNT(e.obj) AS rate
FROM pref a, pref b, pref c, pref d, pref e
WHERE a.usr = '222' # step 1: select a pair of objects A, B, where A is better than B according to user X
AND a.obj = '111'
AND b.usr = a.usr
AND b.ord < a.ord
AND c.obj = a.obj # step 2: find users thinking that object A is better than B
AND d.obj = b.obj
AND d.ord < c.ord
AND d.usr = c.usr
AND e.ord > c.ord # step 3: find objects better than A according to these users
AND e.usr = c.usr
GROUP BY e.obj
ORDER BY rate DESC;
Синонимы:
a
объект A ('111'), текущий пользователь ('222')
b
объект B, хуже чем A согласно текущему пользователю (имеет более низкое значение 'ord' чем A)
c
объект A в очереди другого пользователя
d
объект B в очереди другого пользователя
e
объект лучше чем A в очереди другого пользователя
План выполнения (uo и uo - индексы в соответствии с предложением Quassnoi ):
+----+-------------+-------+------+---------------+------+---------+---------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+---------------------+------+----------------------------------------------+
| 1 | SIMPLE | a | ref | ouo,uo | ouo | 8 | const,const | 1 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | b | ref | ouo,uo | uo | 4 | const | 86 | Using where |
| 1 | SIMPLE | d | ref | ouo,uo | ouo | 4 | db.b.obj | 587 | Using index |
| 1 | SIMPLE | c | ref | ouo,uo | ouo | 8 | const,db.d.usr | 1 | Using where; Using index |
| 1 | SIMPLE | e | ref | uo | uo | 4 | db.d.usr | 80 | Using where |
+----+-------------+-------+------+---------------+------+---------+---------------------+------+----------------------------------------------+
Кажется, что запрос работает нормально, пока набор данных не слишком большой; какие-либо идеи о том, как оптимизировать его для поддержки больших наборов данных?