真的很慢MySQL插入查询

时间:2010-12-21 01:05:12

标签: mysql

我有一张约有五十万条记录的表格。这不是很大。一对varchar(255)字段,一些整数,一个浮点数和几个时间戳。整体上有指数以及外键约束。插入内容永远。我说1-4秒插入一个行。我不得不多次处理缓慢的选择查询,但是我一直试图弄清楚这个插入的内容。

编辑:好的,我真的只是想询问如何调试这个,但是,这里涉及的所有表格。插入“成分”是永远需要的。希望将我的架构的很大一部分投放到网上并不会让我后来咬我......

CREATE TABLE `ingredients` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `quantity` float DEFAULT NULL,
  `food` varchar(255) NOT NULL,
  `unit_id` int(11) DEFAULT NULL,
  `ingredient_group_id` int(11) DEFAULT NULL,
  `order_by` int(11) NOT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  `description` varchar(255) DEFAULT NULL,
  `range` float DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `unit_id` (`unit_id`),
  KEY `ingredient_group_id` (`ingredient_group_id`),
  CONSTRAINT `ingredients_ibfk_1` FOREIGN KEY (`unit_id`) REFERENCES `units` (`id`),
  CONSTRAINT `ingredients_ibfk_2` FOREIGN KEY (`ingredient_group_id`) REFERENCES `ingredient_groups` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=269974 DEFAULT CHARSET=utf8

CREATE TABLE `units` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `abbreviation` varchar(255) CHARACTER SET latin1 NOT NULL,
  `type` int(11) NOT NULL,
  `si` float NOT NULL,
  `lower_bound` float DEFAULT NULL,
  `lower_unit_id` int(11) DEFAULT NULL,
  `upper_bound` float DEFAULT NULL,
  `upper_unit_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `lower_unit_id` (`lower_unit_id`),
  KEY `upper_unit_id` (`upper_unit_id`),
  CONSTRAINT `units_ibfk_1` FOREIGN KEY (`lower_unit_id`) REFERENCES `units` (`id`),
  CONSTRAINT `units_ibfk_2` FOREIGN KEY (`upper_unit_id`) REFERENCES `units` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8

CREATE TABLE `ingredient_groups` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `recipe_id` int(11) NOT NULL,
  `order_by` int(11) NOT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `recipe_id` (`recipe_id`),
  CONSTRAINT `ingredient_groups_ibfk_1` FOREIGN KEY (`recipe_id`) REFERENCES `recipes` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=32739 DEFAULT CHARSET=utf8

3 个答案:

答案 0 :(得分:3)

缺少大量信息,但我首先要检查的是:

  • 如果在MyISAM表上:极其碎片化的文件,尤其是索引文件。使用filefrag进行检查。如果数据库随时间缓慢增长,就会发生这种情况。如果是这样,只需关闭MySQL,复制数据库目录,重命名原始副本和新副本并重启MySQL

  • 如果您使用InnoDB表:基于文件的数据存储,再次过于分散。在这种情况下,碎片可以在文件系统级别(检查和处理如上)或数据存储级别,对于使用InnoDB工具。在最坏的情况下,基于块设备的数据存储(无法获得外部碎片)可能会出现内部碎片的不良情况。

  • 一些基数极低的索引。也就是说,存在很少不同值的非唯一索引,即大量重复。该索引渐近地逼近线性列表,具有O(n)个时间轮廓。这可以是表上的索引,也可以是引用的外部索引。

  • 读者争用。不太可能,但是大量的并发读者可以阻止一个作家。

修改

在阅读完您的定义后,我认为ingredients.unit_idingredients.ingredient_group_id是第一个要检查的候选人,因为它们的基数似乎很低。

第一种不太可能有用(你打算选择用勺子测量的所有成分吗?),所以你可以放弃它。

第二个可能非常有用;但如果成分组很少,则基数可能会非常低,从而降低性能。要提高基数,请添加一些部分以使其更具辨别力。如果查询中没有其他字段可能与组ID一起显示,只需添加主ID或创建日期,使其成为(ingredient_group_id, id)(ingredient_group_id, created_at)。似乎违反直觉,增加复杂性以使其更快,但它确实可以提供帮助。作为奖励,您可以向sort by created_at选择的任何查询添加ingredient_group_id,而不会造成性能损失。

答案 1 :(得分:1)

您可能希望查看ingredients.unit_id索引,因为它的选择性较低。

是同时发生的插入吗?

答案 2 :(得分:1)

原来我有一个触发器正在成为这个bug的牺牲品:

http://bugs.mysql.com/bug.php?id=9021

我把它从IN转到了=,现在插入在0.00秒内运行。

我完全忘了我有一个连接到这张桌子的触发器。这是我的错。对于那些浪费时间试图帮助我的人感到抱歉,但无论如何,非常感谢你。