Вот мой запрос:
SELECT n.id, n.member_id, n.content, n.created_at
FROM notes n
JOIN note_metadata nm ON n.id = nm.note_id
AND nm.meta_key_id = 4 # Nature
AND nm.meta_value = 'Cancellation'
#ORDER BY n.id DESC
LIMIT 10;
Без ORDER BY запрос очень эффективен. Вот как выглядит EXPLAIN для этого:
Однако с ORDER BY запрос замедляется до сканирования. Вот как выглядит EXPLAIN для этого:
Вот CREATE TABLE для заметок:
CREATE TABLE `notes` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`member_id` int(10) unsigned NOT NULL,
`created_by` int(10) unsigned DEFAULT NULL,
`type_id` int(10) unsigned NOT NULL,
`content` text COLLATE utf8mb4_unicode_ci NOT NULL,
`is_public` int(10) unsigned NOT NULL DEFAULT '0',
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
`is_archived` tinyint(3) unsigned DEFAULT '0',
PRIMARY KEY (`id`),
KEY `notes_type_id_foreign` (`type_id`),
KEY `member_id` (`member_id`),
KEY `created_at` (`created_at`),
CONSTRAINT `_notes_type_id_foreign` FOREIGN KEY (`type_id`) REFERENCES `note_types` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21374344 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
Вот CREATE TABLE для note_metadata:
CREATE TABLE `note_metadata` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`note_id` bigint(20) unsigned NOT NULL,
`meta_key_id` int(10) unsigned NOT NULL,
`meta_value` text COLLATE utf8mb4_unicode_ci NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `note_metadata_meta_key_id_foreign` (`meta_key_id`),
KEY `_note_metadata_note_id_foreign` (`note_id`),
CONSTRAINT `_note_metadata_note_id_foreign` FOREIGN KEY (`note_id`) REFERENCES `notes` (`id`),
CONSTRAINT `note_metadata_meta_key_id_foreign` FOREIGN KEY (`meta_key_id`) REFERENCES `note_meta_keys` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4098655 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
Любая идея, как я могу сделать последний запрос — с ORDER BY — таким же быстрым, как первый? Нужно ли мне добавлять новый индекс или что-то в этом роде?


Рассмотрите возможность добавления индекса (note_id,meta_key_id,meta_value) и удаления индекса _note_metadata_note_id_foreign.
Использовать,
SET autocommit=0;
LOCK TABLES note_metadata WRITE;
alter table `note_metadata`
add index note_mkey_mval(note_id,meta_key_id,meta_value),
drop index `_note_metadata_note_id_foreign`;
COMMIT;
UNLOCK TABLES;
Поскольку meta_value определяется как столбец text, при определении ключа вам необходимо указать длину префикса. Вы должны добавить следующий составной индекс:
ALTER TABLE note_metadata
ADD INDEX (meta_key_id, meta_value(20), note_id);
Вы должны изменить пункт ORDER BY на nm.note_id вместо n.id.
Вот db<>рабочий пример.
Создание индекса может помочь.
CREATE INDEX notes_id_idx ON notes(id DESC);
notes.id уже ПК.
У каждой записи в примечании есть соответствующая запись в note_metadata?