Как лучше оптимизировать этот запрос MySQL с помощью подзапросов - PullRequest
0 голосов
/ 24 января 2019

У меня возникли проблемы с оптимизацией запроса mySQL, для которого я использовал подзапросы, чтобы попытаться получить предыдущий и следующий идентификаторы на основе идентификатора в запросе. Когда я использую функцию EXPLAIN в mySQL, это показывает, что один из моих подзапросов проходит через 690k + строк, что, как я предполагаю, влияет на производительность.

Я пытался ограничить подзапросы, чтобы они возвращали только один результат, и использовал MIN и MAX в подзапросах, но оба этих параметра по-прежнему возвращали большие наборы строк.

SELECT c.*, (SELECT id FROM cards WHERE id > '733290' ORDER BY id ASC LIMIT 1) AS 'prev', (SELECT id FROM cards WHERE id < '733290' ORDER BY id DESC LIMIT 1) AS 'next' FROM cards c LEFT JOIN albums a ON (a.id = cs.album_id) WHERE c.id = '733290'

В объяснении таковы были результаты:

id
select_type
table
type
possible_keys
key
key_len
ref
rows
Extra

5
SUBQUERY
cards
range
PRIMARY,user_id
PRIMARY
4
NULL
696177
Using where

4
SUBQUERY
cards
range
PRIMARY,user_id
PRIMARY
4
NULL
4
Using where

Редактировать: Вот определения для таблицы карт:

Keyname    Type    Unique  Packed  Column  Cardinality Collation   Null    Comment
PRIMARY BTREE   Yes No  id  696183  A   No  
user_id BTREE   No  No  user_id 5438    A   No  
album   BTREE   No  No  album   258 A   No

Ответы [ 2 ]

0 голосов
/ 26 января 2019

EXPLAIN предоставляет поддельную информацию, особенно когда задействован LIMIT.

Ваш запрос является оптимальным и в действительности не затронет более 1 строки в каждом направлении.

(а я так и не понял, чего добивается Билл!)

Чтобы получить более надежный счетчик количества затронутых строк, сделайте следующее:

FLUSH STATUS;
SELECT ...;
SHOW SESSION STATUS LIKE 'Handler_read%';

Для аналогичного запроса (для таблицы с 3,1M строк) я получил

+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Handler_read_first    | 0     |
| Handler_read_key      | 3     |
| Handler_read_last     | 0     |
| Handler_read_next     | 0     |
| Handler_read_prev     | 0     |
| Handler_read_rnd      | 0     |
| Handler_read_rnd_next | 0     |
+-----------------------+-------+

Сложите числа (и получите 3); это будет точно (?) сколько строк было затронуто. 3 кажется правильным для вашего запроса.

0 голосов
/ 24 января 2019

Вот попытка:

SELECT c.*, cp.id AS `prev`, cn.id AS `next`
FROM cards c
LEFT JOIN cards cp ON c.id < cp.id
LEFT JOIN cards cpp ON c.id < cpp.id AND cp.id > cpp.id
LEFT JOIN cards cn ON c.id > cn.id
LEFT JOIN cards cnn ON c.id > cnn.id AND cn.id < cnn.id
WHERE c.id = 733290
 AND cpp.id IS NULL
 AND cnn.id IS NULL

Объяснение: Соедините c с cp, у которого есть больший идентификатор, но также убедитесь, что набор строк cpp с идентификатором между c.id и cp.id - пустой набор.То есть внешнее соединение должно возвращать NULL.

Сделайте то же самое для cn.

...