索引创建后 MySQL 查询变慢

时间:2021-06-13 14:21:39

标签: mysql indexing

首先我会写一些关于我的测试表的信息。 这是包含 665647 行数据的书籍表。 您可以在下面看到它的外观。

enter image description here

我对价格相同的图书进行了 10 次相同的查询

select * from books where price = 10

所有 10 个查询的执行时间为 9 秒 663 毫秒。

之后我创建了索引,你可以在这里看到: enter image description here

我尝试再次运行相同的 10 个查询。 他们的执行时间为 21 秒 996 毫秒。

show index from books;

为我显示了非常有线的数据。 可能的值只有一个!

enter image description here

我做错了什么?我确信索引可以使我们的查询更快,而不是更慢。

我找到了这个话题:MySQL index slowing down query 但说实话,我不太明白这个特别是基数列 在我的表格书籍中,此刻我有两个可能的价格字段值 10 和 30 仍然 show index from books; 显示 1 enter image description here

@Edit1 显示创建桌书

结果:

    CREATE TABLE `books` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `description` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `isbn` bigint unsigned NOT NULL,
  `price` double(8,2) unsigned NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  `author_id` bigint unsigned NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `books_isbn_unique` (`isbn`),
  KEY `books_author_id_foreign` (`author_id`),
  KEY `books_price_index` (`price`),
  CONSTRAINT `books_author_id_foreign` FOREIGN KEY (`author_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=665648 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

@Edit2 我添加了新索引 create index nameIndex on books (name) enter image description here 具有大的基数值。

当我尝试执行此查询时 select * from books where name ='Inventore cumque quis.' 在索引创建之前和之后,我可以看到执行时间的差异。 但我仍然不明白索引是如何工作的。我确信一件事 - 如果我在我的数据库中创建新索引,就是使用适合该索引的数据创建新的数据结构。 例如,如果我有价格为 10、30 的 orws,我会得到两个“表格”,其中包含这些价格的行。

2 个答案:

答案 0 :(得分:4)

有这么多行具有相同的 price 是否现实?从查询中返回 444K 行是否现实?我问这些是因为查询优化基于“正常”数据。

索引(例如,INDEX(price))在查找出现次数较少的 price 时很有用。事实上,如果优化器发现要搜索的值出现的时间超过大约 20%,它就会避开索引。相反,它会简单地忽略索引并执行您首先测试的操作——简单地扫描整个表,忽略任何不匹配的行。

你应该能够看到这一点

EXPLAIN select * from books where price = 10

带和不带索引。或者,您可以尝试:

EXPLAIN select * from books IGNORE INDEX(books_price_index) where price = 10
EXPLAIN select * from books FORCE INDEX(books_price_index) where price = 10

但是,...看来优化器并没有忽略索引。我看到 price 的“基数”是“1”,这意味着该列中只有一个不同的值。这个“统计数据”要么不正确,要么具有误导性。请运行它,看看有什么变化:

ANALYZE TABLE books;

这将通过一些随机探测重新计算统计数据,并且可能将“1”更改为“2”。

一般建议:注意针对伪造数据运行的基准测试。

答案 1 :(得分:0)

也许是这个? https://stackoverflow.com/questions/755569/why-does-the-cardinality-of-an-index-in-mysql-remain-unchanged-when-i-add-a-new

创建索引后基数没有更新。尝试运行分析表命令。