Помогите оптимизировать MySQL запрос

0

(с использованием MySQL 4.1.22)

Я не могу заставить этот запрос использовать индекс в большой таблице (200k + rows), он выполняет полное сканирование таблицы на нем. Запрос занимает около 1,2 секунды. Я хочу получить его менее чем на 0,2 секунды, если это возможно.

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

SELECT st_issues.issue_id, st_issues.cat_id,st_categories.name AS cat_name, st_issues.status_id,st_statuses.name AS status_name, st_issues.priority_id,st_priorities.name AS priority_name,st_priorities.color AS color, st_issues.assigned_cid,assigned_u.firstname,assigned_u.lastname,assigned_u.screenname, message, rating, created_by_email,created_by_cid,created_by_uid,by_user.firstname AS by_firstname,by_user.lastname AS by_lastname,by_user.screenname AS by_screenname, st_issues.browser,from_url,created_by_store,created,st_issues.stamp
FROM st_issues
 JOIN st_categories ON (st_issues.cat_id=st_categories.cat_id)
 JOIN st_statuses ON (st_issues.status_id=st_statuses.status_id)
 JOIN st_priorities ON (st_issues.priority_id=st_priorities.priority_id)
 LEFT JOIN users AS assigned_u ON (assigned_u.cid=st_issues.assigned_cid)
 LEFT JOIN users AS by_user ON (by_user.uid=st_issues.created_by_uid)
 LEFT JOIN st_issue_changes ON (st_issues.issue_id=st_issue_changes.issue_id AND change_id=0)
WHERE st_issues.assigned_cid=0

Результаты объяснения:

1, 'SIMPLE', 'st_issues', 'ALL', '', '', , '', 4, 'Using where'
1, 'SIMPLE', 'st_categories', 'eq_ref', 'PRIMARY', 'PRIMARY', 1, 'sg.st_issues.cat_id', 1, ''
1, 'SIMPLE', 'st_priorities', 'eq_ref', 'PRIMARY', 'PRIMARY', 1, 'sg.st_issues.priority_id', 1, ''
1, 'SIMPLE', 'assigned_u', 'ref', 'cid', 'cid', 8, 'sg.st_issues.assigned_cid', 1, ''
1, 'SIMPLE', 'st_statuses', 'ALL', 'PRIMARY', '', , '', 4, 'Using where'
1, 'SIMPLE', 'by_user', 'ALL', '', '', , '', 221623, ''
1, 'SIMPLE', 'st_issue_changes', 'eq_ref', 'PRIMARY', 'PRIMARY', 6, 'sg.st_issues.issue_id,const', 1, ''

Очевидно, проблема связана с соединением on by by_user, поскольку он не использует индекс.

Ниже приведено определение таблицы "users":

CREATE TABLE  `users` (
  `cid` double unsigned NOT NULL auto_increment,
  `uid` varchar(20) NOT NULL default '',
...
  `firstname` varchar(20) default NULL,
  `lastname` varchar(20) default NULL,
...
  PRIMARY KEY  (`uid`),
...
) ENGINE=InnoDB

У кого-нибудь есть идеи, почему он не использует первичный ключ в соединении?
У кого-нибудь есть идеи или подсказки о том, как ускорить этот запрос?

(Я могу добавить определения таблиц других таблиц, если это необходимо/требуется)

Edit:

Вот определение таблицы для st_issues:

CREATE TABLE  `st_issues` (
  `issue_id` int(10) unsigned NOT NULL auto_increment,
  `cat_id` tinyint(3) unsigned NOT NULL default '0',
  `status_id` tinyint(3) unsigned NOT NULL default '0',
  `priority_id` tinyint(3) unsigned NOT NULL default '0',
  `assigned_cid` int(10) unsigned NOT NULL default '0',
  `rating` tinyint(4) default NULL,
  `created_by_email` varchar(255) NOT NULL default '',
  `created_by_cid` int(10) unsigned NOT NULL default '0',
  `created_by_uid` varchar(20) NOT NULL default '',
  `created_by_store` tinyint(3) unsigned NOT NULL default '0',
  `browser` varchar(255) NOT NULL default '',
  `from_url` varchar(255) NOT NULL default '',
  `created` datetime NOT NULL default '0000-00-00 00:00:00',
  `stamp` datetime NOT NULL default '0000-00-00 00:00:00',
  PRIMARY KEY  (`issue_id`),
  KEY `idx_create_by_cid` (`created_by_cid`),
  KEY `idx_create_by_uid` (`created_by_uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  • 0
    Какие индексы у вас есть на st_issues?
  • 0
    какие индексы вы определили?
Показать ещё 1 комментарий
Теги:
optimization

2 ответа

3
Лучший ответ

Это все определение таблицы пользователей?

Потому что он говорит:

) ENGINE = InnoDB

тогда как st_issues говорит:

) ENGINE = InnoDB DEFAULT CHARSET = utf8;

Если ваши две таблицы используют разные сопоставления, два типа данных didatypes для uid и created_by_uid различны, и MySQL должен сделать принуждение набора символов, прежде чем он сможет их сравнить, тем самым побеждая ваш индекс.

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

  • 0
    Бьюсь об заклад, вот в чем проблема, спасибо.
0

Я провел некоторое тестирование и нашел следующие изменения:

  • Добавить индекс на st_issues.assigned_cid.

  • Измените первичный ключ таблицы users на cid вместо uid.

  • Измените условие соединения для by_user, чтобы использовать cid вместо uid:

    LEFT JOIN users AS by_user ON (by_user.cid=st_issues.created_by_cid)
    

Затем я получил следующий отчет EXPLAIN (хотя и с нулевыми строками данных):

+----+-------------+------------------+--------+---------------+--------------+---------+-------------------------------+------+-------------+
| id | select_type | table            | type   | possible_keys | key          | key_len | ref                           | rows | Extra       |
+----+-------------+------------------+--------+---------------+--------------+---------+-------------------------------+------+-------------+
|  1 | SIMPLE      | st_issues        | ref    | assigned_cid  | assigned_cid | 4       | const                         |    1 |             | 
|  1 | SIMPLE      | st_categories    | eq_ref | PRIMARY       | PRIMARY      | 1       | test.st_issues.cat_id         |    1 |             | 
|  1 | SIMPLE      | st_statuses      | eq_ref | PRIMARY       | PRIMARY      | 1       | test.st_issues.status_id      |    1 |             | 
|  1 | SIMPLE      | st_priorities    | eq_ref | PRIMARY       | PRIMARY      | 1       | test.st_issues.priority_id    |    1 |             | 
|  1 | SIMPLE      | assigned_u       | eq_ref | PRIMARY       | PRIMARY      | 8       | test.st_issues.assigned_cid   |    1 |             | 
|  1 | SIMPLE      | by_user          | eq_ref | PRIMARY       | PRIMARY      | 8       | test.st_issues.created_by_cid |    1 |             | 
|  1 | SIMPLE      | st_issue_changes | eq_ref | PRIMARY       | PRIMARY      | 8       | test.st_issues.issue_id,const |    1 | Using index | 
+----+-------------+------------------+--------+---------------+--------------+---------+-------------------------------+------+-------------+

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

Еще одна вещь, которую я хотел бы предложить, - определить ваши таблицы поиска st_categories и st_statuses с помощью натурального ключа, названия категории или состояния. Затем укажите этот естественный ключ из таблицы st_issues, вместо того, чтобы использовать псевдоним tinyint. Преимущество состоит в том, что вам не нужно выполнять эти объединения, чтобы получить название категории или статуса; он уже находится в таблице st_issues.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню