【问题标题】:MySQL Join Optimization TroublesMySQL 连接优化问题
【发布时间】:2011-12-07 03:17:16
【问题描述】:

我正在处理一些利用连接的 MySQL 语句。这些查询的性能似乎相当差,并且可以在查询运行期间降低性能。下面列出了我正在使用的几个查询示例。我是 MySQL JOIN 语句的新手,想知道是否有人可以帮助我优化这些语句以获得更好的性能。

我们使用这两种方法来查询我们的票务系统数据库,以生成一些关于处理的票证类型、处理票证的位置等的报告。

SELECT * FROM tickets t 
LEFT Join customfieldvalues cv1 ON t.ticketid = cv1.typeid 
LEFT Join customfields cf1 ON cv1.customfieldid = cf1.customfieldid 
LEFT Join customfieldoptions co1 on cv1.fieldvalue = co1.customfieldoptionid 
WHERE t.dateline BETWEEN 1314853200 AND 1317445199 
Group by t.ticketid 
Order by t.Dateline asc;

这是从 9 月 1 日到 9 月 30 日的基本查询(未添加过滤)。运行时间 ~140 秒。如果去掉三个连接线,运行时间将缩短到 ~0.01 秒。

SELECT * FROM tickets t 
LEFT Join customfieldvalues cv1 ON t.ticketid = cv1.typeid 
LEFT Join customfields cf1 ON cv1.customfieldid = cf1.customfieldid 
LEFT Join customfieldoptions co1 on cv1.fieldvalue = co1.customfieldoptionid 
LEFT Join customfieldvalues cv2 ON cv1.typeid = cv2.typeid
LEFT Join customfields cf2 ON cv2.customfieldid = cf2.customfieldid
LEFT Join customfieldoptions co2 on cv2.fieldvalue = co2.customfieldoptionid
WHERE t.dateline BETWEEN 1314853200 AND 1317445199 
AND cf1.title ='Customer Type'  AND co1.optionvalue = 'Staff' 
And cf2.title ='Building or Hall' AND co2.optionvalue like '%Stroupe%' 
Group by t.ticketid 
Order by t.Dateline asc;

此查询将是添加了 2 个过滤器的基本查询:客户类型(即员工)和位置建筑物或大厅(Stroupe)。使用与上述相同的时间范围,运行时间约为 0.1 秒。

===============================

编辑:这是 EXPLAIN 命令对列出的第一个查询的输出。

INSERT INTO `table_name` (`id`,`select_type`,`table`,`type`,`possible_keys`,`key`,`key_len`,`ref`,`rows`,`Extra`) VALUES (1,'SIMPLE','t','range','tickets7','tickets7','4',NULL,601,'Using where; Using temporary; Using filesort');
INSERT INTO `table_name` (`id`,`select_type`,`table`,`type`,`possible_keys`,`key`,`key_len`,`ref`,`rows`,`Extra`) VALUES (1,'SIMPLE','cv1','ALL',NULL,NULL,NULL,NULL,104679,'');
INSERT INTO `table_name` (`id`,`select_type`,`table`,`type`,`possible_keys`,`key`,`key_len`,`ref`,`rows`,`Extra`) VALUES (1,'SIMPLE','cf1','eq_ref','PRIMARY','PRIMARY','4','DB.cv1.customfieldid',1,'');
INSERT INTO `table_name` (`id`,`select_type`,`table`,`type`,`possible_keys`,`key`,`key_len`,`ref`,`rows`,`Extra`) VALUES (1,'SIMPLE','co1','eq_ref','PRIMARY','PRIMARY','4','DB.cv1.fieldvalue',1,'');

这是第二个查询的 EXPLAIN 的输出。

id,select_type,table,type,possible_keys,key,key_len,ref,rows,Extra 1,SIMPLE,cf1,ref,"PRIMARY,title1",title1,767,const,1,"使用 where;使用临时;使用文件排序" 1,SIMPLE,co1,ref,"PRIMARY,optionvalue1",optionvalue1,767,const,1,"使用 where" 1,SIMPLE,cf2,ref,"PRIMARY,title1",title1,767,const,1,"使用 where" 1,SIMPLE,t,range,"PRIMARY,tickets7,tickets15,tickets16",tickets7,4,NULL,601,"使用 where" 1,SIMPLE,cv1,ref,customfieldvalues1,customfieldvalues1,8,"DB.cf1.customfieldid,DB.t.ticketid",1,"使用where" 1,SIMPLE,cv2,ref,customfieldvalues1,customfieldvalues1,8,"DB.cf2.customfieldid,DB.t.ticketid",1,"使用where" 1,SIMPLE,co2,eq_ref,PRIMARY,PRIMARY,4,DB.cv2.fieldvalue,1,"使用where"

【问题讨论】:

  • 您是否在 JOIN 操作中涉及的列上创建了索引?
  • @Joe - 我刚刚看了看,是的,似乎每个都有索引。
  • 有两件事可以帮助获得更好的答案:表定义(这样我们可以检查我们期望的列上有索引)和 EXPLAIN 的输出
  • @ Neville - 如何创建此信息以便共享?
  • 在查询前添加 EXPLAIN 这个词,运行它,然后显示结果。

标签: mysql optimization join query-optimization


【解决方案1】:

是你的左连接+where子句=内连接错误的连接,你需要重写查询。

您是说从 cf1 中获取所有行,即使它们不存在,并且只有标题为“客户类型”的行。

如果你将左连接更改为内连接,它会更高效,(虽然可能不会返回你想要的)

【讨论】:

  • @ Kevin - 感谢您的想法。我还是新手。如何创建查询计划?另外,这里的内部连接会更好吗?我已经按照您对 title 和 optionvalue 的建议添加了两个索引(我认为我做得对)。
  • 切换到内部联接对数据库与您的 where 子句结合更有意义,此时 2 个部分发生冲突。
  • 是否有一个公式可以理解连接类型。例如,您提到内部联接基本上是-- INNER JOIN = LEFT JOIN + WHERE CLAUSE ?其他类型还有其他这样的公式吗?
  • 不是一个真正的公式,它是一个常见的错误,可能导致糟糕的执行计划
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-20
  • 1970-01-01
  • 2012-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多