MySQL 查询性能帮助,许多相同的表被连接

标签 mysql performance joomla

我正在编写一个创建 SQL 查询的 PHP 脚本。此脚本和数据库用于 Joomla CMS,特别是查询 SOBIPro 组件的表(以使用在此组件中输入的数据)。然而,由于 SOBI Pro 表的处理方式,每个字段实例在表中都是它自己的行,这意味着为我要拉回的每个字段包含一个单独的表实例。这看起来效率不高,实际上在这一次搜索中它会超时。

SQL查询如下(这是我的PHP代码生成后的):

    SELECT DISTINCT o.id AS entryid, o.parent AS parentID, name.baseData AS title,business.baseData AS business_data,
    contact_fn.baseData AS contact_fn_data ,contact_ln.baseData AS contact_ln_data ,position.baseData AS position_data,
    civic1.baseData AS civic1_data ,civic2.baseData AS civic2_data ,mailing.baseData AS mailing_data,
    community.baseData AS community_data ,municip.baseData AS municip_data ,county.baseData AS county_data,
    province.baseData AS province_data ,country.baseData AS country_data ,postal.baseData AS descr_data,
    phone.baseData AS phone_data ,tollfree.baseData AS tollfree_data ,fax.baseData AS fax_data,
    email.baseData AS email_data ,web.baseData AS web_data ,empTotal.baseData AS empTotal_data
    FROM jos_sobipro_object AS o
    INNER JOIN jos_sobipro_field_data AS name ON name.sid = o.id
    INNER JOIN jos_sobipro_relations AS r ON o.id = r.id
    LEFT JOIN jos_sobipro_field_data AS business ON business.sid = o.id AND business.fid = 36
    LEFT JOIN jos_sobipro_field_data AS contact_fn ON contact_fn.sid = o.id AND contact_fn.fid = 74
    LEFT JOIN jos_sobipro_field_data AS contact_ln ON contact_ln.sid = o.id AND contact_ln.fid = 75
    LEFT JOIN jos_sobipro_field_data AS position ON position.sid = o.id AND position.fid = 76
    LEFT JOIN jos_sobipro_field_data AS civic1 ON civic1.sid = o.id AND civic1.fid = 77
    LEFT JOIN jos_sobipro_field_data AS civic2 ON civic2.sid = o.id AND civic2.fid = 78
    LEFT JOIN jos_sobipro_field_data AS mailing ON mailing.sid = o.id AND mailing.fid = 79
    LEFT JOIN jos_sobipro_field_data AS community ON community.sid = o.id AND community.fid = 80
    LEFT JOIN jos_sobipro_field_data AS municip ON municip.sid = o.id AND municip.fid = 81
    LEFT JOIN jos_sobipro_field_data AS county ON county.sid = o.id AND county.fid = 82
    LEFT JOIN jos_sobipro_field_data AS province ON province.sid = o.id AND province.fid = 83
    LEFT JOIN jos_sobipro_field_data AS country ON country.sid = o.id AND country.fid = 84
    LEFT JOIN jos_sobipro_field_data AS postal ON postal.sid = o.id AND postal.fid = 85
    LEFT JOIN jos_sobipro_field_data AS phone ON phone.sid = o.id AND phone.fid = 86
    LEFT JOIN jos_sobipro_field_data AS tollfree ON tollfree.sid = o.id AND tollfree.fid = 87
    LEFT JOIN jos_sobipro_field_data AS fax ON fax.sid = o.id AND fax.fid = 88
    LEFT JOIN jos_sobipro_field_data AS email ON email.sid = o.id AND email.fid = 89
    LEFT JOIN jos_sobipro_field_data AS web ON web.sid = o.id AND web.fid = 90
    LEFT JOIN jos_sobipro_field_data AS empTotal ON empTotal.sid = o.id AND empTotal.fid = 106
    WHERE o.approved = 1 AND o.oType = 'entry' AND name.fid = 36 AND name.baseData <> ''
    AND name.section = 54 AND r.pid IN (415,418,425,431,458) AND (municip.baseData = "Municipality Name")
    ORDER BY name.baseData ASC

只要不涉及 municip.baseData 搜索,它似乎工作得相当快,在这种情况下,即使在目录中有 15 个条目时它也会失败。必须有更好的方法来设计此 SQL 代码,同时仍然带回所有需要的字段。该查询通过 AJAX 调用,最终目录中将有 2000 多个条目。

编辑:这里是 EXPLAIN 输出,按照要求:

    id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
    1   SIMPLE  name    ref     PRIMARY     PRIMARY     8   const,const     15  Using where; Using temporary; Using filesort
    1   SIMPLE  municip     ref     PRIMARY     PRIMARY     4   const   9   Using where
    1   SIMPLE  o   eq_ref  PRIMARY,oType   PRIMARY     4   [[dbname]].municip.sid  1   Using where
    1   SIMPLE  county  ref     PRIMARY     PRIMARY     4   const   10  
    1   SIMPLE  province    ref     PRIMARY     PRIMARY     4   const   10  
    1   SIMPLE  country     ref     PRIMARY     PRIMARY     4   const   8   
    1   SIMPLE  postal  ref     PRIMARY     PRIMARY     4   const   9   
    1   SIMPLE  business    ref     PRIMARY     PRIMARY     4   const   15  
    1   SIMPLE  contact_fn  ref     PRIMARY     PRIMARY     4   const   9   
    1   SIMPLE  contact_ln  ref     PRIMARY     PRIMARY     4   const   9   
    1   SIMPLE  position    ref     PRIMARY     PRIMARY     4   const   9   
    1   SIMPLE  civic1  ref     PRIMARY     PRIMARY     4   const   10  
    1   SIMPLE  civic2  ref     PRIMARY     PRIMARY     4   const   9   
    1   SIMPLE  phone   ref     PRIMARY     PRIMARY     4   const   10  
    1   SIMPLE  tollfree    ref     PRIMARY     PRIMARY     4   const   9   
    1   SIMPLE  fax     ref     PRIMARY     PRIMARY     4   const   10  
    1   SIMPLE  email   ref     PRIMARY     PRIMARY     4   const   9   
    1   SIMPLE  mailing     ref     PRIMARY     PRIMARY     4   const   11  
    1   SIMPLE  community   ref     PRIMARY     PRIMARY     4   const   9   
    1   SIMPLE  web     ref     PRIMARY     PRIMARY     4   const   10  
    1   SIMPLE  empTotal    ref     PRIMARY     PRIMARY     4   const   10  
    1   SIMPLE  r   ref     PRIMARY     PRIMARY     4   [[dbname]].name.sid     3   Using where; Using index; Distinct

最佳答案

很多时候,当您有一个过度扩展的 JOIN/JOIN/JOIN/etc 时,SQL 引擎将挂起,试图找到小的结果集并以低效的方式回填链接。您的查询看起来不错。

您的 PRIMARY 表(FROM jos_sobipro_object AS o)确实是查询的关键驱动元素。尝试在 MySQL 中添加“STRAIGHT_JOIN”特殊关键字。

SELECT STRAIGHT_JOIN DISTINCT ...查询的其余部分...

STRAIGHT_JOIN 告诉优化器按照我在此处列出的顺序执行查询。如果知道第一个表是查询数据的主要表,它将工作得更快。

也就是说,并没有完全看到索引信息,我会特别在 jos_sobipro_field_data 上有一个索引,以通过(SID,FID)获取“查找”数据。

我不得不对主表中 14+ 百万条记录的政府数据执行类似的方法,并加入 22+ 个查找表。 MySQL 将在 30 多个小时后挂起。通过添加 STRAIGHT_JOIN,查询在大约 3 小时内完成(如预期的那样)。

关于MySQL 查询性能帮助,许多相同的表被连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9936532/

相关文章:

ruby - 为什么在某些情况下 Ruby 的 Hash#values 比 Hash#each_value 更快?

php - 没有人拥有者(99 99)在FTP中由php功能引起?

mysql - 当列名是动态的时,如何从触发器更新表?

mysql - 在行之间循环和复制数据

mysql - 为每个帖子选择最后三个评论者(每组中最大的 n 个)

mysql - GROUP BY 子句的别名?

iphone - 如何提高 iPhone 上 Core Data 对象插入的性能?

performance - 如何高效实现 Youtube 的缩略图预览功能?

php - 从多个数据库导出表并导入到单个数据库

mysql - Joomla 2.5 : You do not have access to the administrator section of this site