性能缓慢的 MySql 查询,替代方案/建议?
Posted
技术标签:
【中文标题】性能缓慢的 MySql 查询,替代方案/建议?【英文标题】:Slow performance MySql query, alternatives / suggestions? 【发布时间】:2017-06-03 11:14:03 【问题描述】:我正在我的硬币网站中实现一个搜索过滤器页面,但现在我有很多条目,速度很慢:
这是未选择过滤器时的查询:
SELECT
i.id_items AS id,
GROUP_CONCAT(DISTINCT iant.translation ORDER BY iant.translation asc SEPARATOR ', ') AS names,
GROUP_CONCAT(DISTINCT iafv.face_value ORDER BY iafv.face_value ASC SEPARATOR ', ') AS facesValues,
GROUP_CONCAT(DISTINCT iacut.translation ORDER BY iacut.translation ASC SEPARATOR ', ') AS currencies,
GROUP_CONCAT(DISTINCT cout.translation ORDER BY cout.translation ASC SEPARATOR ', ') AS countries,
GROUP_CONCAT(DISTINCT iacot.translation ORDER BY iacot.translation ASC SEPARATOR ', ') AS compositions,
GROUP_CONCAT(DISTINCT iacc.catalog_code ORDER BY iacc.catalog_code ASC SEPARATOR ', ') AS catalogCodes,
GROUP_CONCAT(DISTINCT iaio.issues_on ORDER BY iaio.issues_on ASC SEPARATOR ', ') AS issuesOn,
GROUP_CONCAT(DISTINCT iali.last_issues ORDER BY iali.last_issues ASC SEPARATOR ', ') AS latestIssues,
MIN(ucfs.price) AS minPrice,
SUM(ucfs.units) AS totalUnits
FROM
items i
INNER JOIN languages AS l
ON l.language_code = "en"
LEFT JOIN items_atr_faces_values_match AS iafvm
ON iafvm.id_items = i.id_items
LEFT JOIN items_atr_faces_values AS iafv
ON iafv.id_items_atr_faces_values = iafvm.id_items_atr_faces_values
LEFT JOIN items_atr_currencies_match AS iacum
ON iacum.id_items = i.id_items
LEFT JOIN items_atr_currencies_translations AS iacut
ON iacut.id_items_atr_currencies = iacum.id_items_atr_currencies
AND iacut.id_language_code = l.id_languages
LEFT JOIN items_atr_currencies AS iacu
ON iacu.id_items_atr_currencies = iacum.id_items_atr_currencies
LEFT JOIN items_atr_countries_match AS iacoum
ON iacoum.id_items = i.id_items
LEFT JOIN items_atr_countries_translations AS cout
ON cout.id_items_atr_countries = iacoum.id_items_atr_countries
AND cout.id_language_code = l.id_languages
LEFT JOIN items_atr_countries AS cou
ON cou.id_items_atr_countries = iacoum.id_items_atr_countries
LEFT JOIN items_atr_compositions_match AS iacom
ON iacom.id_items = i.id_items
LEFT JOIN items_atr_compositions_translations AS iacot
ON iacot.id_items_atr_compositions = iacom.id_items_atr_compositions
AND iacot.id_language_code = l.id_languages
LEFT JOIN items_atr_compositions AS iaco
ON iaco.id_items_atr_compositions = iacom.id_items_atr_compositions
LEFT JOIN items_atr_catalog_codes_match AS iaccm
ON iaccm.id_items = i.id_items
LEFT JOIN items_atr_catalog_codes AS iacc
ON iacc.id_items_atr_catalog_codes = iaccm.id_items_atr_catalog_codes
LEFT JOIN items_atr_issues_on_match AS iaiom
ON iaiom.id_items = i.id_items
LEFT JOIN items_atr_issues_on AS iaio
ON iaio.id_items_atr_issues_on = iaiom.id_items_atr_issues_on
LEFT JOIN items_atr_last_issues_match AS ialim
ON ialim.id_items = i.id_items
LEFT JOIN items_atr_last_issues AS iali
ON iali.id_items_atr_last_issues = ialim.id_items_atr_last_issues
LEFT JOIN items_atr_names_match AS ianm
ON ianm.id_items = i.id_items
LEFT JOIN items_atr_names_translations AS iant
ON iant.id_items_atr_names = ianm.id_items_atr_names
AND iant.id_language_code = l.id_languages
LEFT JOIN items_atr_names AS ian
ON ian.id_items_atr_names = ianm.id_items_atr_names
LEFT JOIN users AS u On u.status = 'active'
LEFT JOIN users_coins_for_sale AS ucfs
ON ucfs.id_users = u.id_users AND ucfs.id_items = i.id_items
GROUP BY id
ORDER BY 2 asc
LIMIT 0, 20
解释如下:
我正在使用 Group Concat,因为每个项目都可以与属性(名称、面值等)有一个或多个匹配项。
查询需要 1.3 秒才能运行 15k 个条目。这些表最终将有 100k 条目,因此运行查询的时间也会增加......
起初我认为 Group_Concat 负责减慢查询速度,但在删除 LIMIT 0, 20 后,我发现它需要相同的时间才能运行。
我尝试将限制放在子查询中:
...
FROM
(SELECT id_items FROM items LIMIT 0, 20) AS i
INNER JOIN languages AS l
...
现在查询速度很快,但结果不是我预期的。
你们有什么建议可以解决这个问题吗?
另外,我在这个查询中遇到了类似的问题,要计算项目的数量:
SELECT
COUNT(DISTINCT i.id_items) AS number
FROM
items i
INNER JOIN languages AS l
ON l.language_code = "en"
LEFT JOIN items_atr_faces_values_match AS iafvm
ON iafvm.id_items = i.id_items
LEFT JOIN items_atr_faces_values AS iafv
ON iafv.id_items_atr_faces_values = iafvm.id_items_atr_faces_values
LEFT JOIN items_atr_currencies_match AS iacum
ON iacum.id_items = i.id_items
LEFT JOIN items_atr_currencies_translations AS iacut
ON iacut.id_items_atr_currencies = iacum.id_items_atr_currencies
AND iacut.id_language_code = l.id_languages
LEFT JOIN items_atr_currencies AS iacu
ON iacu.id_items_atr_currencies = iacum.id_items_atr_currencies
LEFT JOIN items_atr_countries_match AS iacoum
ON iacoum.id_items = i.id_items
LEFT JOIN items_atr_countries_translations AS cout
ON cout.id_items_atr_countries = iacoum.id_items_atr_countries
AND cout.id_language_code = l.id_languages
LEFT JOIN items_atr_countries AS cou
ON cou.id_items_atr_countries = iacoum.id_items_atr_countries
LEFT JOIN items_atr_compositions_match AS iacom
ON iacom.id_items = i.id_items
LEFT JOIN items_atr_compositions_translations AS iacot
ON iacot.id_items_atr_compositions = iacom.id_items_atr_compositions
AND iacot.id_language_code = l.id_languages
LEFT JOIN items_atr_compositions AS iaco
ON iaco.id_items_atr_compositions = iacom.id_items_atr_compositions
LEFT JOIN items_atr_catalog_codes_match AS iaccm
ON iaccm.id_items = i.id_items
LEFT JOIN items_atr_catalog_codes AS iacc
ON iacc.id_items_atr_catalog_codes = iaccm.id_items_atr_catalog_codes
LEFT JOIN items_atr_issues_on_match AS iaiom
ON iaiom.id_items = i.id_items
LEFT JOIN items_atr_issues_on AS iaio
ON iaio.id_items_atr_issues_on = iaiom.id_items_atr_issues_on
LEFT JOIN items_atr_last_issues_match AS ialim
ON ialim.id_items = i.id_items
LEFT JOIN items_atr_last_issues AS iali
ON iali.id_items_atr_last_issues = ialim.id_items_atr_last_issues
LEFT JOIN items_atr_names_match AS ianm
ON ianm.id_items = i.id_items
LEFT JOIN items_atr_names_translations AS iant
ON iant.id_items_atr_names = ianm.id_items_atr_names
AND iant.id_language_code = l.id_languages
LEFT JOIN items_atr_names AS ian
ON ian.id_items_atr_names = ianm.id_items_atr_names
LEFT JOIN users AS u On u.status = 'active'
LEFT JOIN users_coins_for_sale AS ucfs
ON ucfs.id_users = u.id_users AND ucfs.id_items = i.id_items
LIMIT 1
这需要 0.8 秒。
解释:
我在我的搜索页面中运行了两个查询(需要第二个用于分页),所以最终加载需要 2 秒。现在有 15k 项,所以当我有 100K 时,需要更长的时间。
任何建议将不胜感激。
提前致谢
更新:这里是创建数据:
CREATE TABLE IF NOT EXISTS `items` (
`id_items` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_users` int(11) unsigned NOT NULL DEFAULT '0',
`date` date NOT NULL,
`views` bigint(20) NOT NULL DEFAULT '0',
`status` enum('draft','published') NOT NULL DEFAULT 'draft',
PRIMARY KEY (`id_items`),
UNIQUE KEY `id_items` (`id_items`),
KEY `id_users` (`id_users`),
CONSTRAINT `FK_items_users` FOREIGN KEY (`id_users`) REFERENCES `users` (`id_users`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Lista de items';
CREATE TABLE IF NOT EXISTS `items_atr_catalog_codes` (
`id_items_atr_catalog_codes` int(11) unsigned NOT NULL AUTO_INCREMENT,
`catalog_code` varchar(100) NOT NULL DEFAULT '0',
PRIMARY KEY (`id_items_atr_catalog_codes`),
UNIQUE KEY `id_items_atr_catalog_codes` (`id_items_atr_catalog_codes`),
FULLTEXT KEY `catalog_code` (`catalog_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Los diferentes códigos de catálogo que tienen las monedas';
CREATE TABLE IF NOT EXISTS `items_atr_catalog_codes_match` (
`id_items_atr_catalog_codes_match` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_items_atr_catalog_codes` int(11) unsigned NOT NULL,
`id_items` int(11) unsigned NOT NULL,
PRIMARY KEY (`id_items_atr_catalog_codes_match`),
UNIQUE KEY `id_items_atr_catalog_codes_match` (`id_items_atr_catalog_codes_match`),
KEY `id_items` (`id_items`),
KEY `id_items_atr_catalog_codes` (`id_items_atr_catalog_codes`),
CONSTRAINT `FK_catalog_codes_items_match_catalog_codes` FOREIGN KEY (`id_items_atr_catalog_codes`) REFERENCES `items_atr_catalog_codes` (`id_items_atr_catalog_codes`),
CONSTRAINT `FK_catalog_codes_items_match_items` FOREIGN KEY (`id_items`) REFERENCES `items` (`id_items`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Asociación de monedas con los códigos del catálogo';
CREATE TABLE IF NOT EXISTS `items_atr_compositions` (
`id_items_atr_compositions` int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id_items_atr_compositions`),
UNIQUE KEY `id_items_atr_compositions` (`id_items_atr_compositions`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Lista de las diferentes composiciones';
CREATE TABLE IF NOT EXISTS `items_atr_compositions_match` (
`id_items_atr_compositions_match` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_items_atr_compositions` int(11) unsigned NOT NULL DEFAULT '0',
`id_items` int(11) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id_items_atr_compositions_match`),
UNIQUE KEY `id_items_atr_compositions_match` (`id_items_atr_compositions_match`),
KEY `id_items` (`id_items`),
KEY `id_items_atr_compositions` (`id_items_atr_compositions`),
CONSTRAINT `FK_compositions_items_match_compositions` FOREIGN KEY (`id_items_atr_compositions`) REFERENCES `items_atr_compositions` (`id_items_atr_compositions`),
CONSTRAINT `FK_compositions_items_match_items` FOREIGN KEY (`id_items`) REFERENCES `items` (`id_items`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Las diferentes composiciones que puede tener un item';
CREATE TABLE IF NOT EXISTS `items_atr_compositions_translations` (
`id_items_atr_compositions_translations` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_items_atr_compositions` int(11) unsigned NOT NULL DEFAULT '0',
`id_language_code` int(11) unsigned NOT NULL DEFAULT '0',
`translation` varchar(250) NOT NULL DEFAULT '0',
PRIMARY KEY (`id_items_atr_compositions_translations`),
UNIQUE KEY `id_items_atr_compositions_translations` (`id_items_atr_compositions_translations`),
KEY `id_language_code` (`id_language_code`),
KEY `id_items_atr_compositions` (`id_items_atr_compositions`),
FULLTEXT KEY `translation` (`translation`),
CONSTRAINT `FK_compositions_translations_compositions` FOREIGN KEY (`id_items_atr_compositions`) REFERENCES `items_atr_compositions` (`id_items_atr_compositions`),
CONSTRAINT `FK_compositions_translations_languages` FOREIGN KEY (`id_language_code`) REFERENCES `languages` (`id_languages`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Traducciones de las composiciones';
CREATE TABLE IF NOT EXISTS `items_atr_countries` (
`id_items_atr_countries` int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id_items_atr_countries`),
UNIQUE KEY `id_items_atr_countries` (`id_items_atr_countries`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `items_atr_countries_match` (
`id_items_atr_countries_match` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_items_atr_countries` int(11) unsigned NOT NULL,
`id_items` int(11) unsigned NOT NULL,
PRIMARY KEY (`id_items_atr_countries_match`),
UNIQUE KEY `items_atr_countries_match` (`id_items_atr_countries_match`),
KEY `id_items` (`id_items`),
KEY `id_items_atr_countries` (`id_items_atr_countries`),
CONSTRAINT `FK__countries` FOREIGN KEY (`id_items_atr_countries`) REFERENCES `items_atr_countries` (`id_items_atr_countries`),
CONSTRAINT `FK__items` FOREIGN KEY (`id_items`) REFERENCES `items` (`id_items`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='A que pais pertenece cada item';
CREATE TABLE IF NOT EXISTS `items_atr_countries_translations` (
`id_items_atr_countries_translations` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_items_atr_countries` int(11) unsigned NOT NULL DEFAULT '0',
`id_language_code` int(11) unsigned NOT NULL DEFAULT '0',
`translation` varchar(250) NOT NULL DEFAULT '0',
PRIMARY KEY (`id_items_atr_countries_translations`),
UNIQUE KEY `id_items_atr_countries_translations` (`id_items_atr_countries_translations`),
KEY `id_items_atr_countries` (`id_items_atr_countries`),
KEY `id_language_code` (`id_language_code`),
FULLTEXT KEY `translation` (`translation`),
CONSTRAINT `FK__items_atr_countries` FOREIGN KEY (`id_items_atr_countries`) REFERENCES `items_atr_countries` (`id_items_atr_countries`),
CONSTRAINT `FK_items_atr_countries_translations_languages` FOREIGN KEY (`id_language_code`) REFERENCES `languages` (`id_languages`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `items_atr_currencies` (
`id_items_atr_currencies` int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id_items_atr_currencies`),
UNIQUE KEY `id_items_atr_currencies` (`id_items_atr_currencies`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Diferentes divisas de las monedas';
CREATE TABLE IF NOT EXISTS `items_atr_currencies_match` (
`id_items_atr_currencies_match` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_items_atr_currencies` int(11) unsigned NOT NULL DEFAULT '0',
`id_items` int(11) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id_items_atr_currencies_match`),
UNIQUE KEY `id_items_atr_currencies_match` (`id_items_atr_currencies_match`),
KEY `id_items_atr_currencies` (`id_items_atr_currencies`),
KEY `id_items` (`id_items`),
CONSTRAINT `FK_items_atr_currencies_match_items` FOREIGN KEY (`id_items`) REFERENCES `items` (`id_items`),
CONSTRAINT `FK_items_atr_currencies_match_items_atr_currencies` FOREIGN KEY (`id_items_atr_currencies`) REFERENCES `items_atr_currencies` (`id_items_atr_currencies`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Asociación de las monedas con su divisa';
CREATE TABLE IF NOT EXISTS `items_atr_currencies_translations` (
`id_items_atr_currencies_translations` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_items_atr_currencies` int(11) unsigned NOT NULL DEFAULT '0',
`id_language_code` int(11) unsigned NOT NULL DEFAULT '0',
`translation` varchar(255) NOT NULL DEFAULT '0',
PRIMARY KEY (`id_items_atr_currencies_translations`),
UNIQUE KEY `id_items_atr_currencies_translations` (`id_items_atr_currencies_translations`),
KEY `id_items_atr_currencies` (`id_items_atr_currencies`),
KEY `id_language_code` (`id_language_code`),
FULLTEXT KEY `translation` (`translation`),
CONSTRAINT `FK_items_atr_currencies_translations_items_atr_currencies` FOREIGN KEY (`id_items_atr_currencies`) REFERENCES `items_atr_currencies` (`id_items_atr_currencies`),
CONSTRAINT `FK_items_atr_currencies_translations_languages` FOREIGN KEY (`id_language_code`) REFERENCES `languages` (`id_languages`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Traducciones de las divisas';
CREATE TABLE IF NOT EXISTS `items_atr_faces_values` (
`id_items_atr_faces_values` int(11) unsigned NOT NULL AUTO_INCREMENT,
`face_value` decimal(8,2) unsigned NOT NULL DEFAULT '0.00',
PRIMARY KEY (`id_items_atr_faces_values`),
UNIQUE KEY `id_items_atr_faces_values` (`id_items_atr_faces_values`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Valores faciales de las monedas';
CREATE TABLE IF NOT EXISTS `items_atr_faces_values_match` (
`id_items_atr_faces_values_match` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_items_atr_faces_values` int(11) unsigned NOT NULL DEFAULT '0',
`id_items` int(11) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id_items_atr_faces_values_match`),
UNIQUE KEY `id_items_atr_faces_values_match` (`id_items_atr_faces_values_match`),
KEY `id_items_atr_faces_values` (`id_items_atr_faces_values`),
KEY `id_items` (`id_items`),
CONSTRAINT `FK_items_atr_faces_values_match_items` FOREIGN KEY (`id_items`) REFERENCES `items` (`id_items`),
CONSTRAINT `FK_items_atr_faces_values_match_items_atr_faces_values` FOREIGN KEY (`id_items_atr_faces_values`) REFERENCES `items_atr_faces_values` (`id_items_atr_faces_values`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Asociación de las monedas con sus valores faciales';
CREATE TABLE IF NOT EXISTS `items_atr_issues_on` (
`id_items_atr_issues_on` int(11) unsigned NOT NULL AUTO_INCREMENT,
`issues_on` varchar(6) NOT NULL DEFAULT '0',
PRIMARY KEY (`id_items_atr_issues_on`),
UNIQUE KEY `id_items_atr_issues_on` (`id_items_atr_issues_on`),
FULLTEXT KEY `issues_on` (`issues_on`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Fecha en la que se emitió por primera vez la moneda';
CREATE TABLE IF NOT EXISTS `items_atr_issues_on_match` (
`id_items_atr_issues_on_match` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_items_atr_issues_on` int(11) unsigned NOT NULL,
`id_items` int(11) unsigned NOT NULL,
PRIMARY KEY (`id_items_atr_issues_on_match`),
UNIQUE KEY `id_items_atr_issues_on_match` (`id_items_atr_issues_on_match`),
KEY `id_items_atr_issues_on` (`id_items_atr_issues_on`),
KEY `id_items` (`id_items`),
CONSTRAINT `FK_items_atr_issues_on_match_items` FOREIGN KEY (`id_items`) REFERENCES `items` (`id_items`),
CONSTRAINT `FK_items_atr_issues_on_match_items_atr_issues_on` FOREIGN KEY (`id_items_atr_issues_on`) REFERENCES `items_atr_issues_on` (`id_items_atr_issues_on`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Asociaciones de emisiones con las monedas';
CREATE TABLE IF NOT EXISTS `items_atr_last_issues` (
`id_items_atr_last_issues` int(11) unsigned NOT NULL AUTO_INCREMENT,
`last_issues` varchar(6) NOT NULL DEFAULT '0',
PRIMARY KEY (`id_items_atr_last_issues`),
UNIQUE KEY `id_items_atr_last_issues` (`id_items_atr_last_issues`),
FULLTEXT KEY `last_issues` (`last_issues`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Atributo de última emisión de la moneda';
CREATE TABLE IF NOT EXISTS `items_atr_last_issues_match` (
`id_items_atr_last_issues_match` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_items_atr_last_issues` int(11) unsigned NOT NULL DEFAULT '0',
`id_items` int(11) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id_items_atr_last_issues_match`),
UNIQUE KEY `id_items_atr_last_issues_match` (`id_items_atr_last_issues_match`),
KEY `id_items_atr_last_issues` (`id_items_atr_last_issues`),
KEY `id_items` (`id_items`),
CONSTRAINT `FK_items_atr_last_issues_match_items` FOREIGN KEY (`id_items`) REFERENCES `items` (`id_items`),
CONSTRAINT `FK_items_atr_last_issues_match_items_atr_last_issues` FOREIGN KEY (`id_items_atr_last_issues`) REFERENCES `items_atr_last_issues` (`id_items_atr_last_issues`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Asociaciones entre las últimas emisiones y las monedas';
CREATE TABLE IF NOT EXISTS `items_atr_names` (
`id_items_atr_names` int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id_items_atr_names`),
UNIQUE KEY `id_items_atr_names` (`id_items_atr_names`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Contiene el atributo nombre de los items';
CREATE TABLE IF NOT EXISTS `items_atr_names_match` (
`id_items_atr_names_match` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_items_atr_names` int(11) unsigned NOT NULL DEFAULT '0',
`id_items` int(11) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id_items_atr_names_match`),
UNIQUE KEY `id_items_atr_names_match` (`id_items_atr_names_match`),
KEY `id_items_atr_names` (`id_items_atr_names`),
KEY `id_items` (`id_items`),
CONSTRAINT `FK_items_atr_names_match_items` FOREIGN KEY (`id_items`) REFERENCES `items` (`id_items`),
CONSTRAINT `FK_items_atr_names_match_items_atr_names` FOREIGN KEY (`id_items_atr_names`) REFERENCES `items_atr_names` (`id_items_atr_names`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Asociación del atributo nombre con las monedas';
CREATE TABLE IF NOT EXISTS `items_atr_names_translations` (
`id_items_atr_names_translations` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_items_atr_names` int(11) unsigned NOT NULL DEFAULT '0',
`id_language_code` int(11) unsigned NOT NULL DEFAULT '0',
`translation` varchar(250) NOT NULL DEFAULT '0',
PRIMARY KEY (`id_items_atr_names_translations`),
UNIQUE KEY `id_items_atr_names_translations` (`id_items_atr_names_translations`),
KEY `id_language_code` (`id_language_code`),
KEY `id_items_atr_names` (`id_items_atr_names`),
KEY `STR_LEVE_idx` (`translation`),
FULLTEXT KEY `translation` (`translation`),
CONSTRAINT `FK_items_atr_names_translations_items_atr_names` FOREIGN KEY (`id_items_atr_names`) REFERENCES `items_atr_names` (`id_items_atr_names`),
CONSTRAINT `FK_items_atr_names_translations_languages` FOREIGN KEY (`id_language_code`) REFERENCES `languages` (`id_languages`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Traducciones del atributo nombre';
CREATE TABLE IF NOT EXISTS `users` (
`id_users` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_languages` int(11) unsigned NOT NULL,
`password` char(128) NOT NULL,
`user_name` char(128) NOT NULL,
`last_login` datetime DEFAULT NULL,
`ip_register` varbinary(16) DEFAULT NULL,
`ip_last_login` varbinary(16) DEFAULT NULL,
`creation_date` datetime DEFAULT NULL,
`email` varchar(254) DEFAULT NULL,
`fb_user_id` varchar(255) DEFAULT NULL,
`fb_access_token` varchar(255) DEFAULT NULL,
`regen_password` varchar(254) DEFAULT NULL,
`activation_token` varchar(254) DEFAULT NULL,
`affiliated` varchar(30) NOT NULL DEFAULT 'no',
`credit` decimal(10,2) NOT NULL DEFAULT '0.00',
`status` enum('inactive','active','vacation','deleted') NOT NULL DEFAULT 'inactive',
`news` tinyint(1) NOT NULL DEFAULT '1',
`promotions` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`id_users`),
UNIQUE KEY `email` (`email`),
KEY `id_languages` (`id_languages`),
FULLTEXT KEY `fb_user_id` (`fb_user_id`),
FULLTEXT KEY `email2` (`email`),
FULLTEXT KEY `user_name` (`user_name`),
CONSTRAINT `FK_users_languages` FOREIGN KEY (`id_languages`) REFERENCES `languages` (`id_languages`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Lista de usuarios en la web';
CREATE TABLE IF NOT EXISTS `users_coins_for_sale` (
`id_users_coins_for_sale` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_items` int(11) unsigned NOT NULL,
`id_users` int(11) unsigned NOT NULL,
`units` int(5) unsigned NOT NULL,
`year` varchar(5) NOT NULL,
`grade` enum('good','very_good','fine','very_fine','extra_fine','about_uncirculated','uncirculated','brilliant_uncirculated','proof') NOT NULL,
`price` decimal(8,2) unsigned NOT NULL,
`picture` varchar(500) DEFAULT NULL,
`comment` varchar(500) DEFAULT NULL,
`date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id_users_coins_for_sale`),
UNIQUE KEY `id_users_coins_for_sale_unique` (`id_users_coins_for_sale`),
KEY `id_items` (`id_items`),
KEY `id_users` (`id_users`),
KEY `year` (`year`),
KEY `grade` (`grade`),
KEY `id_users_coins_for_sale` (`id_users_coins_for_sale`),
CONSTRAINT `FK_users_coins_for_sale_items` FOREIGN KEY (`id_items`) REFERENCES `items` (`id_items`),
CONSTRAINT `FK_users_coins_for_sale_users` FOREIGN KEY (`id_users`) REFERENCES `users` (`id_users`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
【问题讨论】:
你听说过使用索引来加速连接吗?除此之外,您的架构看起来相当大。您在这里处理多少条记录? 第二个问题更有趣。请注意,关于性能的问题总是需要针对所有相关表的 CREATE TABLE 语句以及 EXPLAIN 的结果。 @Strawberry 我用数据创建更新了答案以查看数据模型 【参考方案1】:您有一个非常复杂的查询,因为要执行所有笛卡尔积。这有点难以理解,因为您没有提供数据模型。
提高性能的关键是在加入之前进行聚合,这样就不会得到笛卡尔积。有两种方法可以做到这一点。一种是在FROM
子句中预先聚合表。另一种是使用相关子查询。当您进一步过滤行时(比如获得 20 行),相关子查询通常是更好的选择。
您可以通过使用子查询在连接之前进行聚合来简化它。举一个聚合的例子:
SELECT i.id_items AS id,
(SELECT GROUP_CONCAT(iafv.face_value SEPARATOR ', ')
FROM tems_atr_faces_values_match iafvm JOIN
items_atr_faces_values iafv
ON iafv.id_items_atr_faces_values = iafvm.id_items_atr_faces_values AND
iafvm.id_items = i.id_items
) as facesValues
. . .
FROM items i INNER JOIN
languages AS l
ON l.language_code = 'en';
对于此查询,您需要在 items_atr_faces_values_match(id_items, id_items_atr_faces_values)
和 items_atr_faces_values(id_items_atr_faces_values, face_value
上建立索引。
您需要对所有关系重复此操作。
【讨论】:
我通过数据创建更新了答案,以查看具有我拥有的索引的数据模型。现在就尝试做你的建议 我刚刚尝试了您建议的方式link,但运行时间相同,可能少了 100 毫秒 @NicolásGonzález 。 . .子查询应该都是内连接,索引很重要。 感谢@gordon-linoff,看到我之前评论中的链接,我看到索引没有导出,但它们在那里,idk 为什么 heidi 没有导出它们。唯一留下子查询的情况是它按该表排序但没有限制值。我将验证您的答案,因为子查询帮助我解决了问题。再次感谢您的宝贵时间【参考方案2】:表太多。
不要“规范化”简单的东西,例如 face_value 和 issues_on(可能还有其他东西。它会导致额外的JOINs
没有额外的灵活性等。
我看到一个国家 ID,但没有国家名称??最好用这个代替表和id:
country_code CHAR(2) CHARACTER SET ascii
并使用标准的 2 字母国家/地区代码。 (它还将在各种表中用 2 字节字符串替换 4 字节 INT
。
另外,由于PRIMARY KEY
根据定义(在 mysql 中)是UNIQUE
:
PRIMARY KEY(x)
UNIQUE (x) -- DROP this
你需要LEFT
吗?也就是说,“正确”表中的行是否可能丢失?如果没有,请删除LEFT
。
在你清理完这些之后,要求再次审查。
【讨论】:
嗨@rick-james,感谢您的建议。我在国家表中为我的用户使用国家代码,但我不能在 items_atr_country 表中使用国家代码,因为这些项目使用“不存在”的国家,例如“罗马帝国”。我需要左连接,因为某些项目没有某些属性(国家、面值等可能会丢失)并且我需要一个空引用来知道该属性不匹配。感谢您的独特提示,我将摆脱它们。感谢您的评论,我不是数据库专家,我边走边学。 可能缺少的属性可能是,例如face_value
decimal(8,2) unsigned NULL DEFAULT NULL,从而避免了 JOIN。 (除非那里有更多您没有在CREATE TABLE
中显示的信息)。【参考方案3】:
我找到了解决方案,在 0.125 / 0.180 秒内得到结果
诀窍是首先使用您要排序的属性和选定的分页执行子查询,然后在其余连接中使用项目 ID。
例如,选择名称作为要排序的属性:
SELECT
i.id_items AS id,
GROUP_CONCAT(DISTINCT iant.translation ORDER BY iant.translation asc SEPARATOR ', ') AS names,
GROUP_CONCAT(DISTINCT iafv.face_value ORDER BY iafv.face_value ASC SEPARATOR ', ') AS facesValues,
GROUP_CONCAT(DISTINCT iacut.translation ORDER BY iacut.translation ASC SEPARATOR ', ') AS currencies,
GROUP_CONCAT(DISTINCT cout.translation ORDER BY cout.translation ASC SEPARATOR ', ') AS countries,
GROUP_CONCAT(DISTINCT iacot.translation ORDER BY iacot.translation ASC SEPARATOR ', ') AS compositions,
GROUP_CONCAT(DISTINCT iacc.catalog_code ORDER BY iacc.catalog_code ASC SEPARATOR ', ') AS catalogCodes,
GROUP_CONCAT(DISTINCT iaio.issues_on ORDER BY iaio.issues_on ASC SEPARATOR ', ') AS issuesOn,
GROUP_CONCAT(DISTINCT iali.last_issues ORDER BY iali.last_issues ASC SEPARATOR ', ') AS latestIssues,
MIN(ucfs.price) AS minPrice,
SUM(ucfs.units) AS totalUnits
FROM
(SELECT
i.id_items,
GROUP_CONCAT(DISTINCT iant.translation ORDER BY iant.translation asc SEPARATOR ', ') AS names
FROM
items i
INNER JOIN languages AS l ON l.language_code = "en"
LEFT JOIN items_atr_names_match AS ianm ON ianm.id_items = i.id_items
LEFT JOIN items_atr_names_translations AS iant ON iant.id_items_atr_names = ianm.id_items_atr_names
AND iant.id_language_code = l.id_languages
LEFT JOIN items_atr_names AS ian ON ian.id_items_atr_names = ianm.id_items_atr_names
GROUP BY id_items
ORDER BY 2 asc
LIMIT 0, 20) AS i
INNER JOIN languages AS l ON l.language_code = "en"
LEFT JOIN items_atr_faces_values_match AS iafvm ON iafvm.id_items = i.id_items
LEFT JOIN items_atr_faces_values AS iafv ON iafv.id_items_atr_faces_values = iafvm.id_items_atr_faces_values
LEFT JOIN items_atr_currencies_match AS iacum ON iacum.id_items = i.id_items
LEFT JOIN items_atr_currencies_translations AS iacut ON iacut.id_items_atr_currencies = iacum.id_items_atr_currencies AND iacut.id_language_code = l.id_languages
LEFT JOIN items_atr_currencies AS iacu ON iacu.id_items_atr_currencies = iacum.id_items_atr_currencies
LEFT JOIN items_atr_countries_match AS iacoum ON iacoum.id_items = i.id_items
LEFT JOIN items_atr_countries_translations AS cout ON cout.id_items_atr_countries = iacoum.id_items_atr_countries AND cout.id_language_code = l.id_languages
LEFT JOIN items_atr_countries AS cou ON cou.id_items_atr_countries = iacoum.id_items_atr_countries
LEFT JOIN items_atr_compositions_match AS iacom ON iacom.id_items = i.id_items
LEFT JOIN items_atr_compositions_translations AS iacot ON iacot.id_items_atr_compositions = iacom.id_items_atr_compositions AND iacot.id_language_code = l.id_languages
LEFT JOIN items_atr_compositions AS iaco ON iaco.id_items_atr_compositions = iacom.id_items_atr_compositions
LEFT JOIN items_atr_catalog_codes_match AS iaccm ON iaccm.id_items = i.id_items
LEFT JOIN items_atr_catalog_codes AS iacc ON iacc.id_items_atr_catalog_codes = iaccm.id_items_atr_catalog_codes
LEFT JOIN items_atr_issues_on_match AS iaiom ON iaiom.id_items = i.id_items
LEFT JOIN items_atr_issues_on AS iaio ON iaio.id_items_atr_issues_on = iaiom.id_items_atr_issues_on
LEFT JOIN items_atr_last_issues_match AS ialim ON ialim.id_items = i.id_items
LEFT JOIN items_atr_last_issues AS iali ON iali.id_items_atr_last_issues = ialim.id_items_atr_last_issues
LEFT JOIN items_atr_names_match AS ianm ON ianm.id_items = i.id_items
LEFT JOIN items_atr_names_translations AS iant ON iant.id_items_atr_names = ianm.id_items_atr_names AND iant.id_language_code = l.id_languages
LEFT JOIN items_atr_names AS ian ON ian.id_items_atr_names = ianm.id_items_atr_names
LEFT JOIN users AS u On u.status = 'active'
LEFT JOIN users_coins_for_sale AS ucfs ON ucfs.id_users = u.id_users AND ucfs.id_items = i.id_items
GROUP BY id
ORDER BY 2 asc
我希望这个答案可以节省其他人的时间。
和平
【讨论】:
以上是关于性能缓慢的 MySql 查询,替代方案/建议?的主要内容,如果未能解决你的问题,请参考以下文章