flo*_*ank 5 mysql performance query-performance
我不明白为什么这个查询很慢。它运行 3-4 秒。当我删除表上的联接时,wa_file_storage
整个查询运行时间不到 0.02 秒。explain
没有表现出任何特别的东西,至少对我来说没有。我很可能缺乏知识,无法从解释中显示的数据得出正确的结论。我猜这与那里使用的两个索引和密钥长度有关?
我发现这两个条件的结合导致速度变慢:
ON (
`CompanyLogo`.`model` = 'CompanyLogo'
AND
`Companies`.`id` = (`CompanyLogo`.`foreign_key`)
)
Run Code Online (Sandbox Code Playgroud)
当我从中删除 CompanyLogo 或 Companies 条件时,查询再次快速运行。
为什么这个连接 ON 会导致查询性能变得如此糟糕,我该如何修复这种情况?
输出explain
:
explain
仅包含字段的输出foreign_key
(运行23 秒!):
explain
仅包含字段的输出model
(运行 0.015 秒):
查询:
SELECT `Jobs`.`id` AS `Jobs__id`,
`Jobs`.`company_id` AS `Jobs__company_id`,
`Jobs`.`job_category_id` AS `Jobs__job_category_id`,
`Jobs`.`branch_id` AS `Jobs__branch_id`,
`Jobs`.`title` AS `Jobs__title`,
`Jobs`.`reference_number` AS `Jobs__reference_number`,
`Jobs`.`location_same_as_office_address` AS `Jobs__location_same_as_office_address`,
`Jobs`.`country_id` AS `Jobs__country_id`,
`Jobs`.`city` AS `Jobs__city`,
`Jobs`.`type_id` AS `Jobs__type_id`,
`Jobs`.`description` AS `Jobs__description`,
`Jobs`.`contact_first_name` AS `Jobs__contact_first_name`,
`Jobs`.`contact_last_name` AS `Jobs__contact_last_name`,
`Jobs`.`contact_tel` AS `Jobs__contact_tel`,
`Jobs`.`contact_fax` AS `Jobs__contact_fax`,
`Jobs`.`contact_email` AS `Jobs__contact_email`,
`Jobs`.`show_job_on_world_architects` AS `Jobs__show_job_on_world_architects`,
`Jobs`.`total_hits` AS `Jobs__total_hits`,
`Jobs`.`last_activated_on` AS `Jobs__last_activated_on`,
`Jobs`.`active` AS `Jobs__active`,
`Jobs`.`slug` AS `Jobs__slug`,
`Jobs`.`created` AS `Jobs__created`,
`Jobs`.`modified` AS `Jobs__modified`,
`Jobs`.`logo` AS `Jobs__logo`,
`Jobs`.`activation_counter` AS `Jobs__activation_counter`,
`Jobs`.`deactivated_by_client` AS `Jobs__deactivated_by_client`,
`Jobs`.`logo_id` AS `Jobs__logo_id`,
`Countries`.`id` AS `Countries__id`,
`Countries`.`country` AS `Countries__country`,
`Companies`.`id` AS `Companies__id`,
`Companies`.`company` AS `Companies__company`,
`Companies`.`company2` AS `Companies__company2`,
`Companies`.`company3` AS `Companies__company3`,
`Companies`.`street` AS `Companies__street`,
`Companies`.`street2` AS `Companies__street2`,
`Companies`.`pobox` AS `Companies__pobox`,
`Companies`.`postal_code` AS `Companies__postal_code`,
`Companies`.`city` AS `Companies__city`,
`Companies`.`country_id` AS `Companies__country_id`,
`Companies`.`state_id` AS `Companies__state_id`,
`Companies`.`tel1` AS `Companies__tel1`,
`Companies`.`tel2` AS `Companies__tel2`,
`Companies`.`mobile` AS `Companies__mobile`,
`Companies`.`url` AS `Companies__url`,
`Companies`.`url2` AS `Companies__url2`,
`CompanyLogo`.`id` AS `CompanyLogo__id`,
`CompanyLogo`.`user_id` AS `CompanyLogo__user_id`,
`CompanyLogo`.`foreign_key` AS `CompanyLogo__foreign_key`,
`CompanyLogo`.`model` AS `CompanyLogo__model`,
`CompanyLogo`.`filename` AS `CompanyLogo__filename`,
`CompanyLogo`.`filesize` AS `CompanyLogo__filesize`,
`CompanyLogo`.`mime_type` AS `CompanyLogo__mime_type`,
`CompanyLogo`.`extension` AS `CompanyLogo__extension`,
`CompanyLogo`.`hash` AS `CompanyLogo__hash`,
`CompanyLogo`.`path` AS `CompanyLogo__path`,
`CompanyLogo`.`adapter` AS `CompanyLogo__adapter`,
`CompanyLogo`.`created` AS `CompanyLogo__created`,
`CompanyLogo`.`modified` AS `CompanyLogo__modified`,
`Profiles`.`id` AS `Profiles__id`,
`Profiles`.`profile_category_id` AS `Profiles__profile_category_id`,
`Profiles`.`status` AS `Profiles__status`,
`Profiles`.`company_id` AS `Profiles__company_id`,
`Profiles`.`profile_title` AS `Profiles__profile_title`,
`Profiles`.`logo` AS `Profiles__logo`,
`Profiles`.`established` AS `Profiles__established`,
`Profiles`.`employee_number` AS `Profiles__employee_number`,
`Profiles`.`slug` AS `Profiles__slug`,
`Profiles`.`old_slug` AS `Profiles__old_slug`,
`Profiles`.`domain_id` AS `Profiles__domain_id`,
`Profiles`.`language_id` AS `Profiles__language_id`,
`Profiles`.`keywords` AS `Profiles__keywords`,
`Profiles`.`meta_description` AS `Profiles__meta_description`,
`Profiles`.`created` AS `Profiles__created`,
`Profiles`.`modified` AS `Profiles__modified`,
`Profiles`.`hits` AS `Profiles__hits`,
`Profiles`.`like_count` AS `Profiles__like_count`,
`Profiles`.`social_buttons` AS `Profiles__social_buttons`,
`Profiles`.`about` AS `Profiles__about`,
`Profiles`.`team_description` AS `Profiles__team_description`,
`Profiles`.`award_count` AS `Profiles__award_count`,
`Profiles`.`project_count` AS `Profiles__project_count`,
`Profiles`.`exhibition_count` AS `Profiles__exhibition_count`,
`Profiles`.`employee_count` AS `Profiles__employee_count`,
`Profiles`.`publication_count` AS `Profiles__publication_count`,
`Profiles`.`competition_count` AS `Profiles__competition_count`,
`Profiles`.`product_count` AS `Profiles__product_count`,
`Profiles`.`facebook` AS `Profiles__facebook`,
`Profiles`.`twitter` AS `Profiles__twitter`,
`Profiles`.`is_setup` AS `Profiles__is_setup`,
`CountryStates`.`id` AS `CountryStates__id`,
`CountryStates`.`name` AS `CountryStates__name`
FROM `wa_jobs` `Jobs`
LEFT JOIN `wa_countries` `Countries` ON `Countries`.`id` = (`Jobs`.`country_id`)
LEFT JOIN `wa_companies` `Companies` ON `Companies`.`id` = (`Jobs`.`company_id`)
LEFT JOIN `wa_file_storage` `CompanyLogo` ON (`CompanyLogo`.`model` = 'CompanyLogo' AND `Companies`.`id` = (`CompanyLogo`.`foreign_key`))
LEFT JOIN `wa_profiles` `Profiles` ON `Companies`.`id` = (`Profiles`.`company_id`)
LEFT JOIN `wa_country_states` `CountryStates` ON `CountryStates`.`id` = (`Companies`.`state_id`)
ORDER BY `Jobs`.`id` DESC
LIMIT 50
OFFSET 850
Run Code Online (Sandbox Code Playgroud)
wa_file_storage 架构:
CREATE TABLE `wa_file_storage` (
`id` CHAR(36) NOT NULL,
`user_id` CHAR(36) NULL DEFAULT NULL,
`foreign_key` CHAR(36) NULL DEFAULT NULL,
`model` VARCHAR(64) NULL DEFAULT NULL,
`filename` VARCHAR(255) NOT NULL,
`filesize` INT(16) NULL DEFAULT NULL,
`mime_type` VARCHAR(32) NULL DEFAULT NULL,
`extension` VARCHAR(5) NULL DEFAULT NULL,
`hash` VARCHAR(64) NULL DEFAULT NULL,
`path` VARCHAR(255) NOT NULL,
`adapter` VARCHAR(32) NULL DEFAULT NULL COMMENT 'Gaufrette Storage Adapter Class',
`created` DATETIME NULL DEFAULT NULL,
`modified` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `foreign_key_model` (`foreign_key`, `model`),
INDEX `model` (`model`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;
Run Code Online (Sandbox Code Playgroud)
wa_companies 架构:
CREATE TABLE `wa_companies` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`company` VARCHAR(255) NOT NULL,
`company2` VARCHAR(255) NOT NULL,
`company3` VARCHAR(255) NOT NULL,
`street` VARCHAR(255) NOT NULL,
`street2` VARCHAR(255) NOT NULL,
`pobox` VARCHAR(255) NOT NULL,
`postal_code` VARCHAR(255) NULL DEFAULT NULL,
`city` VARCHAR(255) NOT NULL,
`country_id` INT(11) NULL DEFAULT NULL,
`state_id` INT(11) NULL DEFAULT NULL,
`tel1` VARCHAR(255) NOT NULL,
`tel2` VARCHAR(255) NOT NULL,
`mobile` VARCHAR(255) NOT NULL,
`fax` VARCHAR(255) NOT NULL,
`email` VARCHAR(255) NOT NULL,
`url` VARCHAR(255) NOT NULL,
`url_text` VARCHAR(255) NOT NULL,
`url2` VARCHAR(255) NOT NULL,
`url2_text` VARCHAR(255) NOT NULL,
`headoffice_id` INT(11) NULL DEFAULT NULL,
`selection_ranking` VARCHAR(255) NOT NULL,
`positioning` VARCHAR(255) NOT NULL,
`advisor_id` INT(11) NOT NULL,
`status_id` INT(11) NOT NULL DEFAULT '1',
`client_status_id` INT(11) NULL DEFAULT '17',
`invoice_language_id` INT(11) NOT NULL DEFAULT '5',
`total_credits` INT(11) NOT NULL,
`tags` VARCHAR(255) NOT NULL,
`uses_as_own_homepage` INT(11) NOT NULL DEFAULT '0',
`address_checked` INT(11) NOT NULL DEFAULT '0',
`approved` TINYINT(1) NOT NULL DEFAULT '0',
`created` DATETIME NOT NULL,
`modified` DATETIME NOT NULL,
`role` VARCHAR(64) NOT NULL DEFAULT 'basic',
`logo_image_id` VARCHAR(36) NULL DEFAULT NULL,
`branch_count` INT(8) NOT NULL DEFAULT '0',
`profile_constraint_id` INT(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `country_id` (`country_id`),
INDEX `state_id` (`state_id`),
INDEX `headoffice_id` (`headoffice_id`),
INDEX `status_id` (`status_id`),
INDEX `client_status_id` (`client_status_id`),
INDEX `PROFILE_CONSTRAINT_INDEX` (`profile_constraint_id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=78372;
Run Code Online (Sandbox Code Playgroud)
在 IRC 上,我被告知要显示以下结果SHOW VARIABLES LIKE 'char%';
:
主要原因CHAR(36)
是我们在较新的表上使用 UUID。这个数据库已有 12 年以上的历史,涉及约 250 个表,我是来解决这个混乱的问题的。:) 我不介意添加另一个表,但主要思想是该表充当所有文件的参考点,无论它们存储在何处。
事实上,您有 wa_companies.id 的 INT 和 wa_file_storage.foreign_key 的 CHAR(36) ,这是问题的一部分。MySQL 必须在这些数据类型之间进行转换才能进行比较,这将从根本上减慢连接速度。
虽然显示的值对于人类来说看起来是相同的,但对于计算机来说,这些值并不相同,因此在比较之前必须进行转换。进行此比较所需的时间很短,但当您考虑到它必须基本上转换每一行以验证其是否匹配时,时间会增加得非常快。(确切的技术细节可能不准确,但就性能变化而言,总体要点和直觉是正确的。)
构建表的最佳方法是不要使用单个“大型”表,而是创建具有最小大小列的单独的多对多表,以便有效地联接。
此外,通过创建多对多表,您可以通过 wa_file_storage.id 键从该表连接到 wa_file_storage 表。这将使您能够访问聚集索引(也称为主键,至少对于 MySQL InnoDB 表)中存在的所有 SELECTed 列。如果 MySQL 最终使用索引,然后 SELECT 列不在索引中,则最终必须对聚集索引进行第二次查找,才能获取这些值。
请记住,JOIN 并不慢。构造不良的 JOIN 会使 RDBMS 执行大量工作,但速度很慢。保持键较小且数据类型一致,并尽可能连接到主键(或覆盖索引),以使 RDBMS 保持良好和简单的状态。
归档时间: |
|
查看次数: |
3861 次 |
最近记录: |