【问题标题】:multiple joins SQL query optimization多连接 SQL 查询优化
【发布时间】:2017-04-24 19:33:16
【问题描述】:

我有以下疑问:

SELECT 
  COUNT(DISTINCT a0_.id) AS sclr0 
FROM 
  account a0_ 
  INNER JOIN customer c1_ ON (c1_.account = a0_.id) 
  LEFT JOIN sf_user_data s2_ ON (s2_.user_id = a0_.id) 
  LEFT JOIN address a3_ ON (c1_.customer_address = a3_.id) 
WHERE 
  a3_.city IS NOT NULL

产生以下输出:

 sclr0  
+--------+
 298279 

带有以下解释:

 id  select_type    table   partitions  type    possible_keys                                 key                    key_len    ref                               rows    filtered    Extra 
+--+---------------+-------+-----------+-------+--------------------------------------------+-----------------------+-----------+--------------------------------+-------+-----------+-------+
1    SIMPLE         c1_     NULL        ALL     UNIQ_81398E097D3656A4,UNIQ_81398E091193CB3F   NULL                   NULL       NULL                              405508   100.00     NULL
1    SIMPLE         a0_     NULL        eq_ref  PRIMARY                                       PRIMARY                8          evoportail.c1_.account            1        100.00     Using index
1    SIMPLE         s2_     NULL        eq_ref  UNIQ_E904BFD1A76ED395                         UNIQ_E904BFD1A76ED395  8          evoportail.c1_.account            1        100.00     Using index
1    SIMPLE         a3_     NULL        eq_ref  PRIMARY                                       PRIMARY                8          evoportail.c1_.customer_address   1         90.00     Using where

表格中的近似行数:

  • 账号:430000
  • 客户:430000
  • sf_user_data : 115000
  • 地址:550000

现在,这个查询在 3 秒内运行。有什么办法可以加快速度吗?

创建语句:

CREATE TABLE `account` (
  `id` bigint(20) unsigned NOT NULL auto_increment,
  `identifier` varchar(255) collate utf8_bin NOT NULL,
  `hash` varchar(255) collate utf8_bin default NULL,
  `date_create` datetime default NULL,
  `group` varchar(50) collate utf8_bin default NULL,
  `sub_group` varchar(50) collate utf8_bin NOT NULL default 'NULL',
  `date_last_action` datetime default NULL,
  `date_last_connection` datetime default NULL,
  `connection_counter` int(10) unsigned default NULL,
  `connection_since_customer` int(10) unsigned NOT NULL default '0',
  `salt` varchar(255) collate utf8_bin default NULL,
  `roles` longtext collate utf8_bin COMMENT '(DC2Type:array)',
  `is_v3` tinyint(1) NOT NULL default '1',
  `password_token` varchar(255) collate utf8_bin default NULL,
  `password_token_expired_at` datetime default NULL,
  `is_included_in_newsletters` tinyint(1) NOT NULL default '0',
  PRIMARY KEY  (`id`),
  UNIQUE KEY `identifier_UNIQUE` (`identifier`)
) ENGINE=MyISAM AUTO_INCREMENT=434243 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `address` (
  `id` bigint(20) unsigned NOT NULL auto_increment,
  `city` varchar(64) collate utf8_bin default NULL,
  `street` varchar(255) collate utf8_bin default NULL,
  `complement` varchar(128) collate utf8_bin default NULL,
  `zipcode` varchar(16) collate utf8_bin default NULL,
  `country_id` int(11) default NULL,
  `cedex` tinyint(1) NOT NULL default '0',
  `abroad` tinyint(1) NOT NULL default '0',
  PRIMARY KEY  (`id`),
  KEY `IDX_D4E6F81F92F3E70` (`country_id`)
) ENGINE=MyISAM AUTO_INCREMENT=541873 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `customer` (
  `id` bigint(20) unsigned NOT NULL auto_increment,
  `account` bigint(20) unsigned NOT NULL,
  `source` varchar(250) collate utf8_bin NOT NULL default 'DECLARATION',
  `last_source` varchar(250) collate utf8_bin NOT NULL,
  `source_domain_name` varchar(255) collate utf8_bin default NULL,
  `subscription_offer` varchar(255) collate utf8_bin default NULL,
  `formalities_center_address` bigint(20) unsigned default NULL,
  `customer_address` bigint(20) unsigned default NULL,
  `business_address` bigint(20) unsigned default NULL,
  `shipping_address` bigint(20) default NULL,
  `activity` text collate utf8_bin,
  `state` enum('NONE','CREATE','UPDATE','COMPLETE') collate utf8_bin NOT NULL default 'NONE',
  `num_dossier` varchar(255) collate utf8_bin default NULL,
  `email` varchar(255) collate utf8_bin NOT NULL,
  `lastname` varchar(255) collate utf8_bin NOT NULL,
  `firstname` varchar(255) collate utf8_bin NOT NULL,
  `sexe` int(1) NOT NULL default '0',
  `activityset` int(1) NOT NULL default '0',
  `phone` varchar(16) collate utf8_bin NOT NULL,
  `business_name` varchar(255) collate utf8_bin default NULL,
  `payment_method` enum('NONE','CB_OK','CB_KO','CHEQUE_OK','CHEQUE_KO','WAITING','IMPACTPLUS_OK','PRELEV') collate utf8_bin default 'NONE',
  `payment_waiting_comment` text collate utf8_bin,
  `sub_sent_recovery` smallint(6) default '0',
  `transaction_number` varchar(30) collate utf8_bin default NULL,
  `transaction_date` datetime default NULL,
  `properties` set('ACCRE','CFE','WANT_WEBSITE','HAVE_WEBSITE','NEWSLETTER','SUBSCRIBE','OLD_CUSTOMER') collate utf8_bin default NULL,
  `comments` text collate utf8_bin,
  `activity_declaration` varchar(512) collate utf8_bin default NULL COMMENT 'file:///',
  `cfe_center` varchar(255) collate utf8_bin default NULL,
  `date_create` datetime default NULL,
  `date_complete` datetime default NULL,
  `date_subscribe` datetime default NULL,
  `date_next_payement` datetime default NULL,
  `date_ae_subscribe` datetime default NULL,
  `siret` varchar(128) collate utf8_bin default NULL,
  `current_quotation` bigint(20) unsigned default NULL,
  `current_invoice` bigint(20) unsigned default NULL,
  `has_create_quotation` tinyint(1) NOT NULL default '0',
  `has_create_invoice` tinyint(1) NOT NULL default '0',
  `created_by` int(20) NOT NULL default '0',
  `updated_by` int(11) NOT NULL default '0',
  `updated_date` datetime default NULL,
  `abo_running` tinyint(1) NOT NULL default '1',
  `show_bn` tinyint(1) NOT NULL default '1',
  `taxe_type_activite` enum('NULL','ACHAT','SERVICE','BOTH') collate utf8_bin default NULL,
  `taxe_categorie_activite` enum('NULL','COMMERCIALE','ARTISANALE','CIPAV','RSI') collate utf8_bin default NULL,
  `taxe_liberatoire` enum('NULL','OUI','NON') collate utf8_bin default NULL,
  `taxe_statut_accre` enum('NULL','OUI','NON','DK') collate utf8_bin default NULL,
  `know` varchar(50) collate utf8_bin default NULL,
  `sms_relance` int(11) default NULL,
  `fdae` int(1) NOT NULL default '0',
  `display_fdae` tinyint(1) NOT NULL default '0',
  `show_dispense_immat` enum('RCS','RM','RSAC') collate utf8_bin default NULL,
  `show_dispense_immat_city` varchar(255) collate utf8_bin default NULL,
  `subscription_fdae` date default NULL,
  `nbsocial` varchar(30) collate utf8_bin default NULL,
  `atclic` int(1) NOT NULL default '0',
  `merassurance` int(1) NOT NULL default '0',
  `dossier_canceled` tinyint(1) NOT NULL default '0',
  `dossier_canceled_date` datetime default NULL,
  `tva_intra` varchar(20) collate utf8_bin default NULL,
  `site_url` varchar(100) collate utf8_bin default NULL,
  `freeguide` tinyint(1) NOT NULL default '0',
  `hiscox` int(1) NOT NULL default '0',
  `assurland` int(1) NOT NULL default '0',
  `unpaid_advisor` int(11) default NULL,
  `unpaid_date` datetime default NULL,
  `ecl_send` tinyint(1) default NULL,
  `ecl_date` datetime default NULL,
  `birthdateyear` int(11) NOT NULL default '0',
  `quaCategorie` varchar(500) collate utf8_bin default NULL,
  `quaNature` varchar(500) collate utf8_bin default NULL,
  `quaType` varchar(500) collate utf8_bin default NULL,
  `april` int(1) NOT NULL default '0',
  `date_guide` datetime default NULL,
  `no_pub` tinyint(1) NOT NULL default '0',
  `campaign_manual` tinyint(1) NOT NULL default '0',
  `export_matmut` date default NULL,
  `formality_date` datetime default NULL,
  `call_count_commerciaux` int(11) default '0',
  `call_count_assistance` int(11) default '0',
  `call_last` datetime default NULL,
  `prospect` tinyint(1) default NULL,
  `gender_id` int(11) default NULL,
  `birthdate` date default NULL,
  `current_customer_source_history_id` int(11) default NULL,
  `original_customer_source_history_id` int(11) default NULL,
  `bounce` tinyint(1) NOT NULL default '0',
  PRIMARY KEY  (`id`),
  UNIQUE KEY `UNIQ_81398E097D3656A4` (`account`),
  UNIQUE KEY `UNIQ_81398E09E7927C74` (`email`),
  UNIQUE KEY `UNIQ_81398E091193CB3F` (`customer_address`),
  UNIQUE KEY `UNIQ_81398E09507DD4CC` (`business_address`),
  UNIQUE KEY `UNIQ_81398E09BA38C653` (`formalities_center_address`),
  KEY `num_dossier` (`num_dossier`),
  KEY `sub_send_recovery` (`sub_sent_recovery`),
  KEY `dossier_canceled` (`dossier_canceled`),
  KEY `freeguide` (`freeguide`),
  KEY `IDX_81398E09708A0E0` (`gender_id`),
  KEY `IDX_81398E0935655550` (`current_customer_source_history_id`),
  KEY `IDX_81398E0981A1F986` (`original_customer_source_history_id`)
) ENGINE=MyISAM AUTO_INCREMENT=433026 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `sf_user_data` (
  `id` int(11) NOT NULL auto_increment,
  `user_id` bigint(20) unsigned NOT NULL,
  `register_id` int(11) default NULL,
  `insurance_id` int(11) default NULL,
  `activity_started_at` date default NULL,
  `accre_request_accepted` tinyint(1) default NULL,
  `accre_request_accepted_at` date default NULL,
  `declaration_frequency_months` smallint(6) default NULL,
  `declaration_reminder` tinyint(1) default NULL,
  `activities_number` smallint(6) default NULL,
  `computed_main_activity_percent_total` double default NULL,
  `computed_secondary_activity_percent_total` double default NULL,
  `company_address_is_personal_address` tinyint(1) default NULL,
  `register_city` varchar(255) collate utf8_unicode_ci default NULL,
  `invoice_last_increment` smallint(6) NOT NULL default '0',
  `quotation_last_increment` smallint(6) NOT NULL default '0',
  `asset_last_increment` smallint(6) NOT NULL default '0',
  `payplug_parameters` varchar(255) collate utf8_unicode_ci default NULL,
  `displayed_first_connection_dialog` tinyint(1) NOT NULL default '0',
  `displayed_first_invoice_display_dialog` tinyint(1) NOT NULL default '0',
  `payplug_parameters_created_at` date default NULL,
  `payplug_first_payment_at` date default NULL,
  `latest_payplug_http_code` int(11) default NULL,
  `register_number` varchar(255) collate utf8_unicode_ci default NULL,
  `register_code` varchar(255) collate utf8_unicode_ci default NULL,
  `register_bis_city` varchar(255) collate utf8_unicode_ci default NULL,
  `register_bis_number` varchar(255) collate utf8_unicode_ci default NULL,
  `registerBis_id` int(11) default NULL,
  `main_activity_type_id` int(11) default NULL,
  `secondary_activity_type_id` int(11) default NULL,
  `declaration_reminder_popup` tinyint(1) default NULL,
  `declaration_reminder_popup_latest_choice` smallint(6) default NULL COMMENT '1 = Me le rappeler demain, 2 = Ne plus afficher cette alerte',
  `declaration_reminder_popup_latest_choice_date` date default NULL,
  `main_activity_id` int(11) default NULL,
  `secondary_activity_id` int(11) default NULL,
  `primary_socio_economic_classification_id` int(11) default NULL,
  `secondary_socio_economic_classification_id` int(11) default NULL,
  `income_bracket_id` int(11) default NULL,
  `main_activity_custom` varchar(255) collate utf8_unicode_ci default NULL,
  `secondary_activity_custom` varchar(255) collate utf8_unicode_ci default NULL,
  `default_further_information` longtext collate utf8_unicode_ci,
  `gclid` varchar(255) collate utf8_unicode_ci default NULL,
  `main_activity_type_old_id` smallint(6) default NULL,
  `main_activity_nature_old_id` smallint(6) default NULL,
  `secondary_activity_type_old_id` smallint(6) default NULL,
  `secondary_activity_nature_old_id` smallint(6) default NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `UNIQ_E904BFD1A76ED395` (`user_id`),
  UNIQUE KEY `UNIQ_E904BFD1D1E63CD1` (`insurance_id`),
  KEY `IDX_E904BFD14976CB7E` (`register_id`),
  KEY `IDX_E904BFD1DBC024CC` (`registerBis_id`),
  KEY `IDX_E904BFD12E864BE8` (`main_activity_type_id`),
  KEY `IDX_E904BFD132198C62` (`secondary_activity_type_id`),
  KEY `IDX_E904BFD15543A800` (`main_activity_id`),
  KEY `IDX_E904BFD1798B8812` (`secondary_activity_id`),
  KEY `IDX_E904BFD1D17B29D3` (`primary_socio_economic_classification_id`),
  KEY `IDX_E904BFD17758CEBC` (`secondary_socio_economic_classification_id`),
  KEY `IDX_E904BFD1BAF920D3` (`income_bracket_id`)
) ENGINE=MyISAM AUTO_INCREMENT=116384 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

【问题讨论】:

  • 除了解释之外,这种性质的问题总是需要为所有相关表创建 TABLE 语句。对于未从中选择列的 OUTER JOIN 表来说,这也是非常不寻常的。
  • 为什么你认为 3 秒很慢???
  • @Strawberry 使用 create 语句编辑了问题
  • @Rahul 没有其他任何东西,我认为 3 秒对于 sql 查询来说已经太多了。但围绕这个查询,我还有其他几个查询。总共,页面(用于统计的重型 SQL 页面)在 20 秒内加载。我正在尝试通过查询优化它。
  • 那么,第一个问题:为什么选择 MyISAM?

标签: mysql performance join


【解决方案1】:

看来这个简单的修改会更快:

SELECT COUNT(DISTINCT a0_.id) sclr0 
  FROM account a0_ 
  JOIN customer c1_ 
    ON c1_.account = a0_.id
  JOIN address a3_ 
    ON c1_.customer_address = a3_.id

如果数据完整性对您很重要,请考虑切换到 InnoDB。

【讨论】:

  • 这不等同。他可以(应该)完全摆脱left joins2_,但不能用join 替换它。 city 也可以是 null,所以 where 条件必须保留。
  • 哇,真快。不确定您是否看到我对我的评论的编辑。您还必须保持where 条件(所有城市都可以是null,如果他们愿意并且现在可以计数,但不应该)。
【解决方案2】:

LEFT JOIN address a3 更改为普通JOIN。这样,优化器可以考虑从address 开始。并将INDEX(city) 添加到address

目前,EXPLAIN 显示在 3 个表中的每一个中都达到了 405K 行。 (总共 120 万)通过上述更改,优化器将从城市索引开始,在那里查看 1K 行。之后,它将在其他两个表中的每一个中查找 1K 行。 (共 3K)

LEFT JOIN sf_user_data s2_ ON (s2_.user_id = a0_.id) 似乎完全没用;去掉它。 (现在减少到 2K 行)

不要盲目使用(255),使用合理的数字。这样做时,如果identifier 不是很大,则将其设为PRIMARY KEY 并去掉id

很少有 6 个不同的列,每个列都是 UNIQUE。我认为您会因此而遇到业务逻辑问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-30
    • 2018-12-27
    • 1970-01-01
    • 2023-04-08
    • 2012-06-05
    • 1970-01-01
    • 2020-01-02
    • 2021-12-11
    相关资源
    最近更新 更多