MAX в подзапросе вызывает сканирование индексаMySql

Форум по Mysql
Ответить
Anonymous
 MAX в подзапросе вызывает сканирование индекса

Сообщение Anonymous »

Мне трудно понять поведение моих запросов.
Учитывая следующие таблицы:

Код: Выделить всё

CREATE TABLE messages (
id         BINARY(16)    NOT NULL PRIMARY KEY,
chat_id    VARCHAR(128)  NOT NULL,
author_id  VARCHAR(128)  NOT NULL,
created_at BIGINT SIGNED NOT NULL,

content    VARCHAR(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,

UNIQUE INDEX chat_id_created_at(chat_id, created_at DESC)
);

CREATE TABLE chat_users (
user_id            VARCHAR(128)     NOT NULL,
chat_id            VARCHAR(128)     NOT NULL,
active             TINYINT(1)       NOT NULL,
created_at         BIGINT signed    NOT NULL,

PRIMARY KEY (user_id, chat_id),
INDEX chat_users_chat_id(chat_id)
);

и user_id Я хочу получать временные метки последних сообщений во всех чатах, к которым принадлежит пользователь.
С помощьюchat_id_created_at
и user_id code> индекс в сообщениях следующий запрос работает мгновенно:

Код: Выделить всё

explain format=json (
SELECT MAX(m.created_at) FROM messages m WHERE m.chat_id  = 'xyz'
)

EXPLAIN OUTPUT:
{
"query_block": {
"select_id": 1,
"message": "Select tables optimized away"
}
}
но когда я использую тот же запрос в качестве подзапроса, кажется, что все строки для каждого Chat_id сканируются, чтобы получить максимальное значение. В некоторых чатах сотни тысяч сообщений, поэтому работа в них становится медленной.

Код: Выделить всё

explain format=json (
SELECT cu.chat_id,
(SELECT MAX(m.created_at)
FROM messages m WHERE m.chat_id = cu.chat_id),
cu.active
FROM chat_users cu
WHERE cu.user_id = '???'
)

EXPLAIN OUTPUT:
{
"query_block": {
"select_id": 1,
"cost_info": {
"query_cost": "0.85"
},
"table": {
"table_name": "cu",
"access_type": "ref",
"possible_keys": [
"PRIMARY"
],
"key": "PRIMARY",
"used_key_parts": [
"user_id"
],
"key_length": "386",
"ref": [
"const"
],
"rows_examined_per_scan": 6,
"rows_produced_per_join": 6,
"filtered": "100.00",
"cost_info": {
"read_cost": "0.25",
"eval_cost": "0.60",
"prefix_cost": "0.85",
"data_read_per_join": "11K"
},
"used_columns": [
"user_id",
"chat_id",
"active"
]
},
"select_list_subqueries": [
{
"dependent": true,
"cacheable": false,
"query_block": {
"select_id": 2,
"cost_info": {
"query_cost": "4.64"
},
"table": {
"table_name": "m",
"access_type": "ref",
"possible_keys": [
"chat_id_created_at"
],
"key": "chat_id_created_at",
"used_key_parts": [
"chat_id"
],
"key_length": "386",
"ref": [
"cu.chat_id"
],
"rows_examined_per_scan": 39,
"rows_produced_per_join": 39,
"filtered": "100.00",
"using_index": true,
"cost_info": {
"read_cost": "0.73",
"eval_cost": "3.91",
"prefix_cost": "4.64",
"data_read_per_join": "122K"
},
"used_columns": [
"chat_id",
"created_at"
]
}
}
}
]
}
}
Я также пробовал использовать ORDER BY m.created_at DESC LIMIT 1 вместо MAX(m.created_at), но происходит то же самое.Мне кажется, что я упускаю что-то очевидное.

Подробнее здесь: https://stackoverflow.com/questions/793 ... index-scan
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «MySql»