MySQL 首次查询时间长

MySQL Long First Query Time

我有一个网站有两个主要的数据库查询,第一次查询时非常慢 运行,经过一些测试后,它似乎是 MySQL 的问题。如果我 运行 直接在 Sequal Pro 中查询,当我第一次 运行 查询时,它可能需要 4 秒才能到达 运行 但 运行 再次执行相同的查询需要~60 毫秒,本地查询时间与我们服务器上的查询时间大致相同,这让我认为这不是服务器问题。

不完全确定增加缓冲池大小是否有帮助,因为潜在查询组合的数量可能在 800K 左右。

数据库中的table是innodb,两个查询都访问同一个table,有52K条记录,我需要的大部分信息已经组合到一个'searchfield'被索引的字段。

只有查询中使用的字段或 primary/foreign 键被索引。

我尝试将内部联接更改为主查询 "where" 中的 select 语句,但这并没有使查询更快。

查询是

查询 1

SELECT 
  `item_attribute`.`attribute_id` AS `attribute_id`,
  `attribute_value_id` AS `attribute_value_id`,
  `collection_attribute`.`title` AS `ca_title`,
  `collection_attribute`.`type` AS `ca_type`,
  `collection_attribute`.`is_collapsible` AS `ca_is_collapsible`,
  `collection_attribute`.`orderindex` AS `ca_orderindex`,
  `collection_attribute`.`multi_select` AS `ca_multi_select`,
  `item_attribute`.`item_id` AS `item_id`,
  `product`.`id` AS `product_id` 
  FROM `item_attribute`
  INNER JOIN `item` ON item.id = item_attribute.item_id
  INNER JOIN `product` ON product.id = item.product_id
  INNER JOIN `collection_attribute` ON item_attribute.attribute_id = collection_attribute.attribute_id
  INNER JOIN `attribute_value` ON attribute_value.id = item_attribute.attribute_value_id 
  WHERE ((`product`.`searchfilter` LIKE '%c:35∆%') AND (`collection_attribute`.`collection_id`='35')) AND (`attribute_value`.`active`=1)
  GROUP BY `attribute_value_id`

查询 2

SELECT DISTINCT `item_attribute`.`attribute_id` AS `attribute_id`,
  GROUP_CONCAT(item_attribute.attribute_value_id SEPARATOR \"-\") AS `attribute_value`,
  GROUP_CONCAT(attribute_value.title SEPARATOR \" - \") AS `title`
  FROM `item_attribute`
  LEFT JOIN `item` ON item.id = item_attribute.item_id 
  LEFT JOIN `attribute` ON attribute.id = item_attribute.attribute_id 
  LEFT JOIN `attribute_value` ON attribute_value.id = attribute_value_id 
  WHERE (`item`.`product_id`='894') AND (`attribute`.`is_option`=1) 
  GROUP BY `attribute_id`, `item_id`

Table结构

CREATE TABLE `product` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `slug` varchar(255) NOT NULL,
  `sku` varchar(20) NOT NULL,
  `active` tinyint(1) DEFAULT '0',
  `orderindex` int(2) DEFAULT '-1',
  `search` varchar(255) DEFAULT NULL,
  `searchfilter` varchar(255) DEFAULT NULL,
  `created_at` int(11) DEFAULT NULL,
  `updated_at` int(11) DEFAULT NULL,
  `protected` tinyint(1) DEFAULT '0',
  `description` varchar(512) DEFAULT NULL,
  `type_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `product_ibfk_1` (`type_id`),
  KEY `searchfilter` (`searchfilter`),
  CONSTRAINT `product_ibfk_1` FOREIGN KEY (`type_id`) REFERENCES `attribute_value` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1882 DEFAULT CHARSET=utf8;

--

CREATE TABLE `collection_attribute` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `collection_id` int(11) DEFAULT NULL,
  `attribute_id` int(11) DEFAULT NULL,
  `title` varchar(512) NOT NULL,
  `slug` varchar(512) NOT NULL,
  `created_at` int(11) DEFAULT NULL,
  `updated_at` int(11) DEFAULT NULL,
  `active` tinyint(1) DEFAULT '0',
  `orderindex` int(2) DEFAULT '-1',
  `search` varchar(255) DEFAULT NULL,
  `searchfilter` varchar(255) DEFAULT NULL,
  `protected` tinyint(1) DEFAULT '0',
  `is_collapsible` tinyint(1) DEFAULT '0',
  `type` enum('icon','checkbox','checkboxIcon','image') DEFAULT NULL,
  `multi_select` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `collection_attribute_ibfk_1` (`collection_id`),
  KEY `collection_attribute_ibfk_2` (`attribute_id`),
  CONSTRAINT `collection_attribute_ibfk_1` FOREIGN KEY (`collection_id`) REFERENCES `collection` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `collection_attribute_ibfk_2` FOREIGN KEY (`attribute_id`) REFERENCES `attribute` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=140 DEFAULT CHARSET=utf8;

--

    CREATE TABLE `item` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `slug` varchar(255) NOT NULL,
  `title` varchar(255) NOT NULL,
  `pattern_code` varchar(32) NOT NULL,
  `tom_code` varchar(32) NOT NULL,
  `navision_code` varchar(32) NOT NULL,
  `description` varchar(255) DEFAULT NULL,
  `active` tinyint(1) DEFAULT '0',
  `orderindex` int(2) DEFAULT '-1',
  `created_at` int(11) DEFAULT NULL,
  `updated_at` int(11) DEFAULT NULL,
  `search` varchar(1024) DEFAULT NULL,
  `searchfilter` varchar(255) DEFAULT NULL,
  `product_id` int(11) DEFAULT NULL,
  `protected` tinyint(1) DEFAULT '0',
  `pattern_series` varchar(255) DEFAULT NULL,
  `pattern_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `item_ibfk_1` (`product_id`),
  KEY `searchfilter` (`searchfilter`),
  KEY `product_id` (`product_id`),
  KEY `pattern_id` (`pattern_id`),
  CONSTRAINT `item_ibfk_1` FOREIGN KEY (`product_id`) REFERENCES `product` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `item_ibfk_2` FOREIGN KEY (`pattern_id`) REFERENCES `pattern_series` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=50060 DEFAULT CHARSET=utf8;

--

CREATE TABLE `item_attribute` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `item_id` int(11) NOT NULL,
  `attribute_id` int(11) NOT NULL,
  `attribute_value_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `attribute_id` (`attribute_id`),
  KEY `attribute_value_id` (`attribute_value_id`),
  KEY `item_id` (`item_id`),
  CONSTRAINT `item_attribute_ibfk_1` FOREIGN KEY (`attribute_id`) REFERENCES `attribute` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `item_attribute_ibfk_2` FOREIGN KEY (`attribute_value_id`) REFERENCES `attribute_value` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `item_attribute_ibfk_3` FOREIGN KEY (`item_id`) REFERENCES `item` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=857111 DEFAULT CHARSET=utf8;

--

CREATE TABLE `attribute_value` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `slug` varchar(255) NOT NULL,
  `code` varchar(255) DEFAULT NULL,
  `title` varchar(255) NOT NULL,
  `active` tinyint(1) DEFAULT '0',
  `orderindex` int(2) DEFAULT '-1',
  `created_at` int(11) DEFAULT NULL,
  `updated_at` int(11) DEFAULT NULL,
  `search` varchar(255) DEFAULT NULL,
  `searchfilter` varchar(255) DEFAULT NULL,
  `attribute_id` int(11) DEFAULT NULL,
  `protected` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3471 DEFAULT CHARSET=utf8;

--

CREATE TABLE `attribute` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `slug` varchar(255) NOT NULL,
  `code` varchar(255) DEFAULT NULL,
  `is_option` tinyint(1) DEFAULT '0',
  `searches` tinyint(1) DEFAULT '0',
  `option_type` enum('dropdown','switch','fingersizes') DEFAULT NULL,
  `option_label` varchar(32) DEFAULT NULL,
  `active` tinyint(1) DEFAULT '0',
  `orderindex` int(2) DEFAULT '-1',
  `created_at` int(11) DEFAULT NULL,
  `updated_at` int(11) DEFAULT NULL,
  `search` varchar(255) DEFAULT NULL,
  `searchfilter` varchar(255) DEFAULT NULL,
  `protected` tinyint(1) DEFAULT '0',
  `option_requires` int(11) DEFAULT NULL,
  `option_depends` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `is_option` (`is_option`)
) ENGINE=InnoDB AUTO_INCREMENT=47 DEFAULT CHARSET=utf8;

任何关于如何改进初始查询时间的建议都会很棒

提前致谢:)

-- 编辑 --

解释 SELECT 查询 1

解释SELECT查询2

启动服务器后第一次执行查询时,缓存中没有任何内容,因此查询需要从磁盘中获取内容。由于缓存,访问相同表的相同部分的所有后续查询都会快得多。这是 "normal".

如果您启用了 "Query cache"(它可能默认启用),那么您第二次 运行 完全 相同的查询,它将立即从查询缓存中找到结果。 "exactly" 我的意思是连空白 space 都没有改变。几乎所有 "production" 服务器最好关闭查询缓存。

innodb_buffer_pool_size 应该是可用 RAM 的大约 70%。更改值不会影响针对冷缓存的 SELECT,但可能 help/hurt 后续 运行。这似乎与您的情况无关,因为第二个 运行 非常快。

请提供 EXPLAIN SELECT ... 以便我们了解优化器如何决定执行它们。

LIKE '%c:35∆%' -- 由于前导通配符,无法使用索引。

什么是 item_ids

item_attribute 是 EAV 架构模式。这很糟糕。这两个查询都很丑陋,并且可伸缩性受到损害。它可能有助于 some 摆脱 id 并从其他字段的适当组合中创建复合 PRIMARY KEY。希望是使用与数据聚类的 PRIMARY KEY 而不是必须从辅助键反弹。 More discussion of EAV.

假设它的基数很低,索引可能永远不会被使用:
is_option (is_option)