我有一张约有五十万条记录的表格。这不是很大。一对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
答案 0 :(得分:3)
缺少大量信息,但我首先要检查的是:
如果在MyISAM表上:极其碎片化的文件,尤其是索引文件。使用filefrag
进行检查。如果数据库随时间缓慢增长,就会发生这种情况。如果是这样,只需关闭MySQL,复制数据库目录,重命名原始副本和新副本并重启MySQL
如果您使用InnoDB表:基于文件的数据存储,再次过于分散。在这种情况下,碎片可以在文件系统级别(检查和处理如上)或数据存储级别,对于使用InnoDB工具。在最坏的情况下,基于块设备的数据存储(无法获得外部碎片)可能会出现内部碎片的不良情况。
一些基数极低的索引。也就是说,存在很少不同值的非唯一索引,即大量重复。该索引渐近地逼近线性列表,具有O(n)个时间轮廓。这可以是表上的索引,也可以是引用的外部索引。
读者争用。不太可能,但是大量的并发读者可以阻止一个作家。
修改强>:
在阅读完您的定义后,我认为ingredients.unit_id
和ingredients.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秒内运行。
我完全忘了我有一个连接到这张桌子的触发器。这是我的错。对于那些浪费时间试图帮助我的人感到抱歉,但无论如何,非常感谢你。