Я вижу, что мой запрос выполняет полное сканирование таблицы и занимает много времени. Я слышал, что создание индексов ускорит это, и я добавил некоторые к таблицам. Существуют ли какие-либо другие индексы, которые я должен создать, чтобы ускорить этот запрос?
Мой запрос:
SELECT p.id, n.people_type_id, n.full_name, n.post, p.nick,
p.key_name, p.email, p.internal_user_id FROM email_routing e
JOIN people_emails p ON p.id=e.receiver_email_id
JOIN people n ON n.id = p.people_id
WHERE e.message_id = 897360 AND e.basket=1
Вот результат EXPLAIN:
EXPLAIN SELECT p.id, n.people_type_id, n.full_name, n.post, p.nick, p.key_name, p.email, p.internal_user_id FROM email_routing e JOIN people_emails p ON p.id=e.receiver_email_id JOIN people n ON n.id = p.people_id WHERE e.message_id = 897360 AND e.basket=1
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE n NULL ALL PRIMARY NULL NULL NULL 1 100.00 NULL
1 SIMPLE p NULL ALL PRIMARY NULL NULL NULL 3178 10.00 Using where; Using join buffer (Block Nested Loop)
1 SIMPLE e NULL ref bk1 bk1 4 server.p.id 440 1.00 Using where; Using
И вот таблицы strucutre:
SHOW CREATE TABLE people_emails;
CREATE TABLE 'people_emails' (
'id' int(11) NOT NULL AUTO_INCREMENT,
'nick' varchar(255) NOT NULL,
'email' varchar(255) NOT NULL,
'key_name' varchar(255) NOT NULL,
'people_id' int(11) NOT NULL,
'status' int(11) NOT NULL DEFAULT '0',
'activity' int(11) NOT NULL,
'internal_user_id' int(11) NOT NULL,
PRIMARY KEY ('id'),
FULLTEXT KEY 'email' ('email')
) ENGINE=MyISAM AUTO_INCREMENT=22114 DEFAULT CHARSET=utf8
SHOW CREATE TABLE email_routing;
CREATE TABLE 'email_routing' (
'id' int(11) NOT NULL AUTO_INCREMENT,
'message_id' int(11) NOT NULL,
'sender_email_id' int(11) NOT NULL,
'receiver_email_id' int(11) NOT NULL,
'basket' int(11) NOT NULL,
'status' int(11) NOT NULL,
'popup' int(11) NOT NULL DEFAULT '0',
'tm' int(11) NOT NULL DEFAULT '0',
KEY 'id' ('id'),
KEY 'bk1' ('receiver_email_id','status','sender_email_id','message_id','basket'),
KEY 'bk2' ('sender_email_id','tm')
) ENGINE=InnoDB AUTO_INCREMENT=1054618 DEFAULT CHARSET=utf8
SHOW CREATE TABLE people;
CREATE TABLE 'people' (
'id' int(11) NOT NULL AUTO_INCREMENT,
'fname' varchar(255) CHARACTER SET cp1251 NOT NULL,
'lname' varchar(255) CHARACTER SET cp1251 NOT NULL,
'patronymic' varchar(255) CHARACTER SET cp1251 NOT NULL,
'gender' tinyint(1) NOT NULL,
'full_name' varchar(255) NOT NULL DEFAULT ' ',
'category' int(11) NOT NULL,
'people_type_id' int(255) DEFAULT NULL,
'tags' varchar(255) CHARACTER SET cp1251 NOT NULL,
'job' varchar(255) CHARACTER SET cp1251 NOT NULL,
'post' varchar(255) CHARACTER SET cp1251 NOT NULL,
'profession' varchar(255) CHARACTER SET cp1251 DEFAULT NULL,
'zip' varchar(16) CHARACTER SET cp1251 NOT NULL,
'country' int(11) DEFAULT NULL,
'region' varchar(10) NOT NULL,
'city' varchar(255) CHARACTER SET cp1251 NOT NULL,
'address' varchar(255) CHARACTER SET cp1251 NOT NULL,
'address_date' date DEFAULT NULL,
'inner' tinyint(4) NOT NULL,
'contact_through' varchar(255) DEFAULT '',
'next_call' date NOT NULL,
'additional' text CHARACTER SET cp1251 NOT NULL,
'user_id' int(11) NOT NULL,
'changed' datetime NOT NULL,
'status' int(11) DEFAULT NULL,
'nick' varchar(255) DEFAULT NULL,
'birthday' date DEFAULT NULL,
'last_update_ts' timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
'area' text NOT NULL,
'reviewed_' tinyint(4) NOT NULL,
'phones_old' text NOT NULL,
'post_sticker' text NOT NULL,
'permissions' int(120) NOT NULL DEFAULT '0',
'internal_user_id' int(11) NOT NULL,
PRIMARY KEY ('id'),
KEY 'most_used' ('category','status','city','lname','next_call'),
KEY 'registrars' ('category','status','contact_through','next_call'),
FULLTEXT KEY 'lname' ('lname'),
FULLTEXT KEY 'fname' ('fname'),
FULLTEXT KEY 'mname' ('patronymic'),
FULLTEXT KEY 'Full Name' ('full_name')
) ENGINE=MyISAM AUTO_INCREMENT=415009 DEFAULT CHARSET=utf8
Как выбрать столбцы для построения индексов, нужно также выбрать текстовые столбцы или только работать с числами столбцов
email_routing
INDEX ( message_id, basket, -- first, in either order
receiver_email_id ) -- for "covering"
Ваш bk1
начинается с receiver_email_id
; это не так хорошо.
WHERE
, которые тестируются с помощью =
.WHERE
, GROUP BY
и ORDER BY
(нет в вашем случае); порядок важен, но выходит за рамки этого обсуждения.TEXT
, который не может быть в индексе. Затем перейдите к другим таблицам. В обоих JOINs
кажется, что они будут поражены их PRIMARY KEYs
(JOIN x ON x.id =...
)
Дополнительная дискуссия: Поваренная книга для создания индексов
По другим вопросам...
Вы действительно должны перейти в InnoDB. Начиная с 5.6, он включает FULLTEXT
, но есть некоторые отличия. В частности, вам может потребоваться больше полнотекстовых индексов. Например, для MATCH(lname, fname)
требуется FULLTEXT(lname, fname)
.
Вы действительно хотите придерживаться cp1251
? Это ограничивает вашу интернализацию главным образом английским, русским, болгарским, сербским и македонским языками. И неясно, насколько хорошо FULLTEXT
(MyISAM или InnoDB) будет работать с теми неанглийскими языками.
INTs
всегда 4 байта; рассмотрите возможность использования меньших версий.
Есть ли только один people
? Оптимизатор решил, что это лучший стол для начала, но это не так. Я надеюсь, что мой улучшенный индекс на email_routing
соберет его, начиная с этой таблицы, что определенно будет оптимальным.
У таблицы email_routing, похоже, есть 1054618 строк.
И вы пытаетесь найти одну строку, через message_id.
e.message_id = 897360
BUT message_id необходимо проиндексировать, чтобы ускорить запрос.
message_id является частью индекса bk1
, но этого недостаточно, потому что message_id не является первым bk1
индекса.