Запрос очень эффективен без ORDER BY, замедляет сканирование с ORDER BY

Вот мой запрос:

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_metadata?

Jonathan Willcock 02.08.2023 08:47
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
2
1
51
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Рассмотрите возможность добавления индекса (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;

Индексы с несколькими столбцами

Правильный способ использования LOCK TABLES и UNLOCK TABLES с транзакционными таблицами, такими как таблицы InnoDB

Ответ принят как подходящий

Поскольку 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 уже ПК.
user1191247 02.08.2023 13:50

Другие вопросы по теме