У меня есть база данных MySql с 4 таблицами (намного больше, чем на самом деле, но только эти 4 имеют отношение к вопросу), позволяет называть их A, B, C и D. Вот схема :wierd MySql join behavior
CREATE TABLE A
(
pKey INT NOT NULL AUTO_INCREMENT,
name NVARCHAR(50),
PRIMARY KEY(pKey),
UNIQUE INDEX(name)
);
CREATE TABLE C
(
pKey INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(pKey)
);
CREATE TABLE B
(
pKey INT NOT NULL AUTO_INCREMENT,
aKey INT NOT NULL,
cKey INT NOT NULL,
PRIMARY KEY(pKey),
UNIQUE INDEX UniqueKey (aKey, cKey),
FOREIGN KEY(aKey) REFERENCES A(pKey),
FOREIGN KEY(cKey) REFERENCES C(pKey)
);
CREATE TABLE D
(
pKey INT NOT NULL AUTO_INCREMENT,
cKey INT NOT NULL,
PRIMARY KEY(pKey),
INDEX(cKey),
FOREIGN KEY(cKey) REFERENCES C(pKey)
);
Я бегу следующий запрос:
SELECT
--stuff...
FROM A
INNER JOIN B
ON A.pKey=B.aKey
INNER JOIN C
ON B.cKey=C.pKey
INNER JOIN D
ON D.cKey=C.pKey
WHERE
A.name=parameter_1;
беда в том, что это большая база данных работает на одном сервере, и большинство таблиц имеют 100К + записи, и его не редкость для таблицу, чтобы сломать 10 миллионов записей. Одна таблица имеет более 200 миллионов записей.
Оставив в стороне любые проблемы с MySql и архитектурой (я застрял с обоими), я получаю некоторое нечетное поведение с вышеуказанным запросом, когда я использую объяснение по этому запросу. Из-за этого поведения у меня есть несколько вопросов. Сначала я покажу странное поведение.
Если я просто ОБЪЯВЛЯЮТ указанный выше запрос в MySql, то получаю ссылки, которые я ожидал бы в столбце ref вывода EXPLAIN. Тем не менее, мне нужно запустить этот запрос в качестве подзапроса большего запроса. EXPLAINning большего запроса дает мне что-то подобное для вышеупомянутого запроса (это просто строки большего запроса, которые соответствуют таблицам в запросе):
+----+-------------+-------+-------+---------------------+---------+---------+-----------------+-------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------------+---------+---------+-----------------+-------+--------------------------+
| 1 | SIMPLE | A | const | PRIMARY,key1,key2 | key1 | 38 | | 1 | |
| 1 | SIMPLE | D | index | key3 | key3 | 12 | NULL | 73868 | Using index |
| 1 | SIMPLE | C | index | PRIMARY,key3 | PRIMARY | 8 | NULL | 1 | |
| 1 | SIMPLE | B | ref | key4,UniqueKey,key6 | key4 | 12 | const,DB.D.key3 | 1 | Using where; Using index |
+----+-------------+-------+-------+---------------------+---------+---------+-----------------+-------+--------------------------+
MySql делает два индекс сканирования, и один исй тип join. Я могу немного улучшить это, если использовать указательные подсказки, но только немного. Ранее я сказал, что этот запрос выполняется как подзапрос. Вот формат этого другого запроса:
SELECT
--stuff
FROM
(
--sub-query1
) a
INNER JOIN
(
--the query I have a question about
) b
ON a.c1=b.c2
Оптимизатор полностью игнорирует таблицу C в пользу делать присоединиться на двух иностранных ключевых столбцов, B.cKey = D.cKey. Итак, вот вопрос 1) Почему оптимизатор игнорирует таблицу C, как это?
Далее, даже если я использую подсказки индекса, и он игнорирует таблицу C, он по-прежнему выполняет сканирование индекса, чтобы присоединиться к B и D, несмотря на соответствующие индексы. Почему?
В приведенном выше объяснении это показывает, что в таблице D. имеется 73 868 строк. На данный момент существует 73 568 строк. Одна из других таблиц, запрашиваемых (не показана в этом вопросе), содержит около 100 миллионов строк, поэтому оптимизация этого довольно важна. Для полного запроса результат столбца строк равен 2.37E42. И да, я уже рассмотрел способы уменьшить количество таблиц в запросе; информация, которую мне нужно получить, требует, чтобы каждая таблица, к которой я обращался, и я не могу изменить архитектуру базы данных.
Наконец, единственное, что я могу здесь изменить, это запрос и индексы/ограничения. Я застрял со всем остальным, так как это уже существовавшая система. Есть ли другие способы, которыми я могу оптимизировать эту операцию больше?
Спасибо!
EDIT: Я исправил форматирование для супер запроса.
Я добавил указатель, который вы предложили, и не было никакой разницы. В таблице C фактически больше столбцов, чем один первичный ключ, и я выбираю значения из некоторых из этих столбцов. Поскольку я не думал, что эти дополнительные столбцы имеют отношение к операции JOIN, я не включил их. – wizard07KSU