MySql Рекомендатель производительности от элемента к элементу - PullRequest
0 голосов
/ 11 июля 2019

Я вижу необъяснимые проблемы с производительностью запросов 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 запрос выполняет сканирование таблицы и выполняется быстрее.
Почему ??

1 Ответ

0 голосов
/ 12 июля 2019

Изменение

PRIMARY KEY (`item_i`,`also_i`)

до

KEY (`item_i`)
KEY (`also_i`)

казалось, решил проблему.

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',
  KEY `count_i` (`count_i`),
  KEY `item_i` (`item_i`),
  KEY `also_i` (`also_i`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

дает производительность

200 min:113 max:85
400 min:148 max:193
600 min:225 max:268
800 min:292 max:362
1000 min:333 max:450
1200 min:360 max:536
1400 min:521 max:618
1600 min:607 max:727
1800 min:698 max:789
2000 min:767 max:841
2200 min:765 max:952
2400 min:1000 max:987
2600 min:1011 max:1241
2800 min:1118 max:1186

, что выглядит разумно, хотя я бы хотел, чтобы это было быстрее. Буду признателен за предложения по реструктуризации этого для повышения производительности.

  • Попытка «ИСПОЛЬЗОВАТЬ ИНДЕКС (ПЕРВИЧНЫЙ)» для принудительного использования используемого ключа была медленнее.
  • Удаление индекса на count_i было медленнее.

Изменение ДВИГАТЕЛЯ = ПАМЯТЬ, так как это таблица только для чтения, которая достаточно мала, чтобы поместиться в память (образ памяти таблицы 200 МБ на компьютере с 16 ГБ), получая:

200 min:16 max:23
400 min:28 max:38
600 min:46 max:56
800 min:58 max:69
1000 min:71 max:89
1200 min:100 max:99
1400 min:105 max:99
1600 min:116 max:132
1800 min:126 max:153
2000 min:139 max:165
2200 min:158 max:181
2400 min:171 max:194
2600 min:197 max:208
2800 min:203 max:223

Это кажется очень разумным для моих целей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...