MySQL, нужно несколько предложений по производительности на мой запрос соответствия - PullRequest
2 голосов
/ 02 октября 2010

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

~ РЕДАКТИРОВАТЬ ~ Этот запрос создает список записей, ключевые слова которых совпадают с ключевыми словами запрашиваемой программы (записи). Мой сайт является каталогом загрузки программного обеспечения. И этот список используется на странице списка программ, чтобы показать другие подобные программы. PadID - это первичный ключ записей программы в моей базе данных.

~ РЕДАКТИРОВАТЬ ~

Вот мой запрос

 select match_keywords.PadID, count(match_keywords.Word) as matching_words 
 from keywords current_program_keywords 
 inner join keywords match_keywords on
       match_keywords.Word=current_program_keywords.Word 
 where match_keywords.Word IS NOT NULL 
 and current_program_keywords.PadID=44243 
 group by match_keywords.PadID 
 order by matching_words DESC 
 LIMIT 0,11;

Вот объяснил запрос. alt text

Вот некоторые примеры данных, однако я сомневаюсь, что вы сможете увидеть влияние любых изменений производительности без дополнительных данных, которые я могу предоставить, если хотите.

 CREATE TABLE IF NOT EXISTS `keywords` (
   `Word` varchar(20) NOT NULL,
   `PadID` bigint(20) NOT NULL,
   `LetterIdx` varchar(1) NOT NULL,
   KEY `Word` (`Word`),
   KEY `LetterIdx` (`LetterIdx`),
   KEY `PadID_2` (`PadID`,`Word`)
 ) ENGINE=MyISAM DEFAULT CHARSET=latin1;

 INSERT INTO `keywords` (`Word`, `PadID`, `LetterIdx`) VALUES
 ('tv', 44243, 'T'),
 ('satellite tv', 44243, 'S'),
 ('satellite tv to pc', 44243, 'S'),
 ('satellite', 44243, 'S'),
 ('your', 44243, 'X'),
 ('computer', 44243, 'C'),
 ('pc', 44243, 'P'),
 ('soccer on your pc', 44243, 'S'),
 ('sports on your pc', 44243, 'S'),
 ('television', 44243, 'T');

Я пытался добавить индекс, но это не имеет большого значения.

 ALTER TABLE `keywords` ADD INDEX ( `PadID` ) 

Ответы [ 3 ]

1 голос
/ 02 октября 2010

Вы можете найти это полезным, если я вас правильно понял.Решение использует преимущества кластерных индексов первичного ключа innodb (http://pastie.org/1195127)

РЕДАКТИРОВАТЬ: вот некоторые ссылки, которые могут оказаться интересными:

http://dev.mysql.com/doc/refman/5.0/en/innodb-index-types.html

http://dev.mysql.com/doc/refman/5.0/en/innodb-adaptive-hash.html

drop table if exists programmes;
create table programmes
(
prog_id mediumint unsigned not null auto_increment primary key,
name varchar(255) unique not null
)
engine=innodb;

insert into programmes (name) values 
('prog1'),('prog2'),('prog3'),('prog4'),('prog5'),('prog6');


drop table if exists keywords;
create table keywords
(
keyword_id mediumint unsigned not null auto_increment primary key,
name varchar(255) unique not null
)
engine=innodb;

insert into keywords (name) values 
('tv'),('satellite tv'),('satellite tv to pc'),('pc'),('computer');


drop table if exists programme_keywords;
create table programme_keywords
(
keyword_id mediumint unsigned not null,
prog_id mediumint unsigned not null,
primary key (keyword_id, prog_id), -- note clustered composite primary key
key (prog_id)
)
engine=innodb;

insert into programme_keywords values 

-- keyword 1
(1,1),(1,5),

-- keyword 2
(2,2),(2,4),

-- keyword 3
(3,1),(3,2),(3,5),(3,6),

-- keyword 4
(4,2),

-- keyword 5
(5,2),(5,3),(5,4);

/*
efficiently list all other programmes whose keywords match that of the 
programme currently being queried (for instance prog_id = 1) 
*/


drop procedure if exists list_matching_programmes;

delimiter #

create procedure list_matching_programmes
(
in p_prog_id mediumint unsigned
)
proc_main:begin

select
 p.*
from
 programmes p
inner join
(
 select distinct -- other programmes with same keywords as current
  pk.prog_id
 from
  programme_keywords pk
 inner join
 (
  select keyword_id from programme_keywords where prog_id = p_prog_id
 ) current_programme -- the current program keywords
 on pk.keyword_id = current_programme.keyword_id
 inner join programmes p on pk.prog_id = p.prog_id 

) matches 
on matches.prog_id = p.prog_id
order by
 p.prog_id;

end proc_main #


delimiter ;

call list_matching_programmes(1);
call list_matching_programmes(6); 


explain
select
 p.*
from
 programmes p
inner join
(
 select distinct
  pk.prog_id
 from
  programme_keywords pk
 inner join
 (
  select keyword_id from programme_keywords where prog_id = 1
 ) current_programme
 on pk.keyword_id = current_programme.keyword_id
 inner join programmes p on pk.prog_id = p.prog_id 

) matches 
on matches.prog_id = p.prog_id
order by
 p.prog_id;

РЕДАКТИРОВАТЬ: добавлены функции char_idx по запросу

alter table keywords add column char_idx char(1) null after name;

update keywords set char_idx = upper(substring(name,1,1));

select * from keywords;

explain
select
 p.*
from
 programmes p
inner join
(
 select distinct
  pk.prog_id
 from
  programme_keywords pk
 inner join
 (
  select keyword_id from keywords where char_idx = 'P' -- just change the driver query
 ) keywords_starting_with
 on pk.keyword_id = keywords_starting_with.keyword_id
) matches 
on matches.prog_id = p.prog_id
order by
 p.prog_id;
1 голос
/ 02 октября 2010

Хорошо, после просмотра вашей базы данных, я думаю, что в запросе не так много места для улучшения, на самом деле на моем тестовом сервере с индексом на Word требуется всего 0,15 с, без индекса - почти в 4 разамедленнее.

В любом случае, я думаю, что внесение изменений в структуру базы данных f00, и я сказал вам, что это улучшит время отклика.

Также отбросьте индекс PadID_2, как сейчасбесполезно и это только замедлит твои записи.Что вы должны сделать, но для очистки базы данных необходимо избегать дублирования пары «ключевое слово-prodId», сначала удалив все дубликаты, которые в настоящее время находятся в БД (около 90 тыс. В моем тесте с 3/4 вашей БД), что сократит время запроса и даст значимые результаты.,Если вы запрашиваете progId с дублированным ключевым словом ABC для progdID2, то progID2 будет на вершине o других progID с таким же ключевым словом ABC, но не дублируется, в моих тестах я видел progID, который получил еще несколько совпадений с тем жеprogID я запрашиваю.После удаления дубликатов из БД вам потребуется изменить приложение, чтобы избежать этой проблемы снова в будущем, и просто для безопасности вы можете добавить первичный ключ (или индекс с уникальным активированным) в Word + ProgID.

1 голос
/ 02 октября 2010

Попробуйте этот подход, не уверен, поможет ли он, но, по крайней мере, он другой:

select PadID, count(Word) as matching_words
from keywords k
where Word in (
  select Word 
  from keywords
  where PadID=44243 )
group by PadID 
order by matching_words DESC 
LIMIT 0,11

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

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