Оптимизация запросов в журнале медленных запросов MySQL - PullRequest
1 голос
/ 07 ноября 2011

Наша база данных настроена так, что у нас есть таблица credentials, которая содержит несколько различных типов учетных данных (логины и т. П.). Также есть таблица credential_pairs, которая связывает некоторые из этих типов вместе (например, у пользователя может быть пароль и токен безопасности).

В попытке выяснить, соответствует ли пара, существует следующий запрос:

SELECT DISTINCT cp.credential_id FROM credential_pairs AS cp
INNER JOIN credentials AS c1 ON (cp.primary_credential_id   = c1.credential_id)
INNER JOIN credentials AS c2 ON (cp.secondary_credential_id = c2.credential_id)
WHERE c1.data = AES_ENCRYPT('Some Value 1', 'encryption key')
AND   c2.data = AES_ENCRYPT('Some Value 2', 'encryption key');

Этот запрос работает нормально и дает нам именно то, что нам нужно. ОДНАКО, он постоянно отображается в медленном журнале запросов (возможно, из-за отсутствия индексов?). Когда я прошу MySQL «объяснить» запрос, он дает мне:

+----+-------------+-------+------+--------------------------------------------------------+---------------------+---------+-------+-------+--------------------------------+
| id | select_type | table | type | possible_keys                                          | key                 | key_len | ref   | rows  | Extra                          |
+----+-------------+-------+------+--------------------------------------------------------+---------------------+---------+-------+-------+--------------------------------+
|  1 | SIMPLE      | c1    | ref  | credential_id_UNIQUE,credential_id,ix_credentials_data | ix_credentials_data | 22      | const |     1 | Using where; Using temporary   |
|  1 | SIMPLE      | c2    | ref  | credential_id_UNIQUE,credential_id,ix_credentials_data | ix_credentials_data | 22      | const |     1 | Using where                    |
|  1 | SIMPLE      | cp    | ALL  | NULL                                                   | NULL                | NULL    | NULL  | 69197 | Using where; Using join buffer |
+----+-------------+-------+------+--------------------------------------------------------+---------------------+---------+-------+-------+--------------------------------+

У меня такое ощущение, что последняя запись (где она показывает 69197 строк), вероятно, является проблемой, но я FAR из DBA ... помогите?


таблица учетных данных:

CREATE TABLE  `credentials` (
  `hidden_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `credential_id` varchar(255) NOT NULL,
  `data` blob NOT NULL,
  `credential_status` varchar(100) NOT NULL,
  `insert_date` datetime NOT NULL,
  `insert_user` int(10) unsigned NOT NULL,
  `update_date` datetime DEFAULT NULL,
  `update_user` int(10) unsigned DEFAULT NULL,
  `delete_date` datetime DEFAULT NULL,
  `delete_user` int(10) unsigned DEFAULT NULL,
  `is_deleted` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`hidden_id`,`credential_id`),
  UNIQUE KEY `credential_id_UNIQUE` (`credential_id`),
  KEY `credential_id` (`credential_id`),
  KEY `data` (`data`(10)),
  KEY `credential_status` (`credential_status`(10))
) ENGINE=InnoDB AUTO_INCREMENT=1572 DEFAULT CHARSET=utf8;

credential_pairs Таблица:

CREATE TABLE  `credential_pairs` (
  `hidden_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `credential_id` varchar(255) NOT NULL,
  `primary_credential_id` varchar(255) NOT NULL,
  `secondary_credential_id` varchar(255) NOT NULL,
  `is_deleted` tinyint(1) DEFAULT NULL,
  PRIMARY KEY (`hidden_id`,`credential_id`),
  KEY `primary_credential_id` (`primary_credential_id`(10)),
  KEY `secondary_credential_id` (`secondary_credential_id`(10))
) ENGINE=InnoDB AUTO_INCREMENT=500 DEFAULT CHARSET=latin1;

Индексы учетных данных:

+-------------+------------+----------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+
| Table       | Non_unique | Key_name             | Seq_in_index | Column_name   | Collation | Cardinality | Sub_part | Packed | Null | Index_type     | Comment |
+-------------+------------+----------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+
| credentials |          0 | PRIMARY              |            1 | hidden_id     | A         |      186235 |     NULL | NULL   |      | BTREE      |         |
| credentials |          0 | PRIMARY              |            2 | credential_id | A         |      186235 |     NULL | NULL   |      | BTREE      |         |
| credentials |          0 | credential_id_UNIQUE |            1 | credential_id | A         |      186235 |     NULL | NULL   |      | BTREE      |         |
| credentials |          1 | credential_id        |            1 | credential_id | A         |      186235 |     NULL | NULL   |      | BTREE      |         |
| credentials |          1 | ix_credentials_data  |            1 | data          | A         |      186235 |       20 | NULL   |      | BTREE      |         |
+-------------+------------+----------------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+

credential_pair Indexes:

+------------------+------------+---------------------------------------------+--------------+-------------------------+-----------+-------------+----------+--------+------+------------+---------+
| Table            | Non_unique | Key_name                                    | Seq_in_index | Column_name             | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+------------------+------------+---------------------------------------------+--------------+-------------------------+-----------+-------------+----------+--------+------+------------+---------+
| credential_pairs |          0 | PRIMARY                                     |            1 | hidden_id               | A         |       69224 |     NULL | NULL   |      | BTREE      |         |
| credential_pairs |          0 | PRIMARY                                     |            2 | credential_id           | A         |       69224 |     NULL | NULL   |      | BTREE      |         |
| credential_pairs |          1 | ix_credential_pairs_credential_id           |            1 | credential_id           | A         |       69224 |       36 | NULL   |      | BTREE      |         |
| credential_pairs |          1 | ix_credential_pairs_primary_credential_id   |            1 | primary_credential_id   | A         |       69224 |       36 | NULL   |      | BTREE      |         |
| credential_pairs |          1 | ix_credential_pairs_secondary_credential_id |            1 | secondary_credential_id | A         |       69224 |       36 | NULL   |      | BTREE      |         |
+------------------+------------+---------------------------------------------+--------------+-------------------------+-----------+-------------+----------+--------+------+------------+---------+

Примечания по обновлению:

AFAICT: DISTINCT был излишним ... ничего действительно не нужно, поэтому я уронил его. В попытке последовать совету Фабрицио, чтобы получить информацию о поиске в credential_pairs, я изменил утверждение так:

SELECT credential_id 
FROM credential_pairs cp
WHERE cp.primary_credential_id = (SELECT credential_id FROM credentials WHERE data = AES_ENCRYPT('value 1','enc_key')) AND
    cp.secondary_credential_id = (SELECT credential_id FROM credentials WHERE data = AES_ENCRYPT('value 2','enc_key'))

И .... ничего. Утверждение занимает столько же времени, а объяснение выглядит примерно так же. Итак, я добавил индекс к первичным и вторичным столбцам с помощью:

ALTER TABLE credential_pairs ADD INDEX `idx_credential_pairs__primary_and_secondary`(`primary_credential_id`, `secondary_credential_id`);

И ... ничего.

+----+-------------+-------------+-------+---------------------+---------------------------------------------+---------+------+-------+--------------------------+
| id | select_type | table       | type  | possible_keys       | key                                         | key_len | ref  | rows  | Extra                    |
+----+-------------+-------------+-------+---------------------+---------------------------------------------+---------+------+-------+--------------------------+
|  1 | PRIMARY     | cp          | index | NULL                | idx_credential_pairs__primary_and_secondary | 514     | NULL | 69217 | Using where; Using index |
|  3 | SUBQUERY    | credentials | ref   | ix_credentials_data | ix_credentials_data                         | 22      |      |     1 | Using where              |
|  2 | SUBQUERY    | credentials | ref   | ix_credentials_data | ix_credentials_data                         | 22      |      |     1 | Using where              |
+----+-------------+-------------+-------+---------------------+---------------------------------------------+---------+------+-------+--------------------------+

Он говорит, что использует индекс, но все равно выглядит как сканирование таблицы. Итак, я добавил совместный ключ (согласно комментарию ниже):

ALTER TABLE credential_pairs ADD KEY (primary_credential_id, secondary_credential_id);

И ... тот же результат, что и с индексом (они функционально одинаковы?).

1 Ответ

0 голосов
/ 07 ноября 2011

DISTINCT - это то, что генерирует «Использовать временное», вы обычно хотите избегать его, когда это возможно

Кроме того, вы сканируете всю таблицу credential_pair, поскольку у вас нет никаких условий против нее, поэтому нетиспользуются индексы и вся таблица возвращается перед применением WHERE

надеюсь, что это имеет смысл

EDIT / ADD

Попробуйте начать с другоготаблица, если я правильно понимаю, у вас есть таблица A, таблица B и таблица AB, и вы начинаете выбор с AB, попробуйте запустить его с A

Я не проверял это, но вы могли быпопробуйте:

SELECT cp.credential_id
FROM credentials AS c1
    LEFT JOIN credential_pairs AS cp ON (c1.credential_id = cp.primary_credential_id)
    LEFT JOIN credentials AS c2 ON (cp.secondary_credential_id = c2.credential_id)
WHERE
    c1.data = AES_ENCRYPT('Some Value 1', 'encryption key')
    AND c2.data = AES_ENCRYPT('Some Value 2', 'encryption key');

Мне повезло в прошлом, перемещая выбранные таблицы вокруг

...