Я вижу необъяснимые проблемы с производительностью запросов MySql.
Данные представляют собой таблицу MySql InnoDB с 3,85 миллионами строк данных корреляции между элементами.
For item "item_i", another item "also_i" was ordered by "count_i" people.
CREATE TABLE `hl_also2sm` (
`item_i` int(10) unsigned NOT NULL DEFAULT '0',
`also_i` int(10) unsigned NOT NULL DEFAULT '0',
`count_i` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`item_i`,`also_i`),
KEY `count_i` (`count_i`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
Примеркорреляция выполняется путем получения списка элементов, поиска соответствующих элементов и возврата приблизительного времени, которое потребовался для выполнения запроса MySql.
// Javascript in NodeJS with MySql, on Debian Linux
var sql = require('./routes/sqlpool'); // connects to DB
var cmd = util.promisify(sql.cmd); // Promise of raw MySql command function
async function inquiry(NumberOfItems){
// generate random list of items to perform correlation against
var rtn = await cmd(`select DISTINCT item_i from hl_also2sm order by RAND() limit ${NumberOfItems}`);
var items_l = rtn.map((h)=>{return h.item_i});
var ts = Date.now();
// get top 50 correlated items
var c = `select also_i,COUNT(*) as cnt,SUM(count_i) as sum from hl_also2sm
where item_i IN (${items_l.join(",")})
AND also_i NOT IN (${items_l.join(",")})
group by also_i
order by cnt DESC,sum DESC limit 50`;
await cmd(c);
var MilliSeconds = Date.now()-ts;
return MilliSeconds;
};
Чтобы проверить это для диапазона элементов
async function inquiries(){
for (items=200;items<3000;items+=200) {
var Data = [];
for (var i=0;i<10;i++) {
Data.push(await inquiry(items));
}
Data.sort();
console.log(`${items} items - min:${Data[0]} max:${Data[9]}`);
}
Результат:
200 items - min:315 max:331
400 items - min:1214 max:1235
600 items - min:2669 max:2718
800 items - min:4796 max:4823
1000 items - min:6872 max:7006
1200 items - min:134 max:154
1400 items - min:147 max:169
1600 items - min:162 max:198
1800 items - min:190 max:212
2000 items - min:210 max:244
2200 items - min:237 max:258
2400 items - min:248 max:293
2600 items - min:263 max:302
2800 items - min:292 max:322
, что очень удивительно.
Почему 2000 предметов более чем в 25 раз быстрее, чем 1000 предметов ??
Выбор 1000 предметов EXPLAIN -
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
| 1 | SIMPLE | hl_also2sm | index | PRIMARY | count_i | 4 | NULL | 4043135 | Using where; Using index; Using temporary; Using filesort |
Выбор 2000 EXPLAIN -
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
| 1 | SIMPLE | hl_also2sm | range | PRIMARY | PRIMARY | 4 | NULL | 758326 | Using where; Using temporary; Using filesort |
Я выполнял это много раз, каждый из которых приводил к схожим результатам.
Да, многие из моих пользователей проявили интерес к тысячам элементов посредством просмотров страниц, комментариев, просмотра изображений или оформления заказов.Я хотел бы подготовить для них хорошее «вам также может понравиться».
Краткое изложение проблемы
select also_i,
COUNT(*) as cnt,
SUM(count_i) as sum
from hl_also2sm
where item_i IN (...) -- Varying the number of IN items
AND also_i NOT IN (...) -- Varying the number of IN items
group by also_i
order by cnt DESC, sum DESC
limit 50
Для <= 1K элементов в <code>INсписки, запрос использует KEY(count_i)
, работает медленнее.
Для> 1K элементов в списках IN
запрос выполняет сканирование таблицы и выполняется быстрее.
Почему ??