【问题标题】:Optimization of a MySQL query in php在 php 中优化 MySQL 查询
【发布时间】:2015-09-26 16:12:15
【问题描述】:

如何优化以下查询

CREATE TABLE $fullTableName AS (
SELECT COUNT(*) AS `impCnt`,
IF(COUNT(*)>7,7,COUNT(*)) AS `impGroup`,
MIN(ad.`created`) AS `dateFirstImp`,
ad.sid,
IF(cl.`clicks` IS NULL, 0, cl.`clicks`) AS `clickCnt`,
st.`panelistID` AS panelistID,
SUBSTRING_INDEX(GROUP_CONCAT(NULLIF(lbs.`site`, '') ORDER BY lbs.`table-order`,lbs.`value-order` ASC SEPARATOR '~'),'~',1) as 'site',
SUBSTRING_INDEX(GROUP_CONCAT(NULLIF(lbs.`dimension`, '') ORDER BY lbs.`table-order`,lbs.`value-order` ASC SEPARATOR '~'),'~',1) as 'dimension'
FROM table1 ad
LEFT JOIN (
    SELECT t.`parameter` as 'parameter', v.`value` as 'value',
    IF(FIND_IN_SET('site',t.attributes),v.`site`,null) as 'site',
    IF(FIND_IN_SET('placement',t.attributes),v.`placement`,null) as 'placement',
    IF(FIND_IN_SET('format',t.attributes),v.`format`,null) as 'format',
    IF(FIND_IN_SET('creative',t.attributes),v.`creative`,null) as 'creative',
    IF(FIND_IN_SET('mediaOwner',t.attributes),v.`mediaOwner`,null) as 'mediaOwner',
    IF(FIND_IN_SET('targeting',t.attributes),v.`targeting`,null) as 'targeting',
    IF(FIND_IN_SET('dimension',t.attributes),v.`dimension`,null) as 'dimension',
    t.`order` as 'table-order', v.`order` as 'value-order' FROM table2 t
    JOIN table3 v ON (t.tableID=v.tableID) WHERE t.campaignID = 1856
    AND t.`active`=1 AND t.`ignore`=0 ORDER BY t.`order`,v.`order`
) lbs ON ($string)
LEFT JOIN (
    SELECT cl2.`memberid` as memberid,
    cl2.`panelid` as panelid,COUNT(*) as clicks
    FROM table4 cl2 WHERE 1 AND (1) GROUP BY cl2.`memberid`,cl2.`panelid`
) cl
ON (ad.`memberid`=cl.`memberid` AND ad.`panelid`=cl.`panelid`)
LEFT JOIN table5 st
ON (ad.`memberid`=st.`panelistID` AND ad.`panelid`=st.`panelID`)
JOIN table6 ef
ON (ef.`panelID`=st.`panelID` AND ef.`panelistID`=st.`panelistID`)
WHERE 1 AND (1) GROUP BY ad.`memberid`, ad.`panelid` ORDER BY ad.`memberid` ASC, ad.`panelid` ASC)

【问题讨论】:

  • 您是否检查过与查询优化有关的类似问题?如果没有,请检查它们并注意查询中提供的信息。如果您不这样做,那么没有人可以帮助您优化查询(我们没有您的数据,我们没有相同的 MySQL 设置/服务器硬件,因此我们无法运行查询)。跨度>
  • 我们来看看EXPLAIN SELECT ...SHOW CREATE TABLE
  • JOIN ( SELECT ... ) JOIN ( SELECT ... ) 效率特别低;你能避免这样的多个子查询吗?

标签: php mysql optimization


【解决方案1】:

想到了各种各样的问题...首先,为了便于阅读,对查询进行了一些清理...

SELECT 
      COUNT(*) AS impCnt,
      IF( COUNT(*) > 7, 7 , COUNT(*) ) AS impGroup,
      MIN(ad.created) AS dateFirstImp,
      ad.sid,
      IF(cl.clicks IS NULL, 0, cl.clicks ) AS clickCnt,
      st.panelistID,
      SUBSTRING_INDEX(GROUP_CONCAT(NULLIF(lbs.site, '') ORDER BY lbs.`table-order`, lbs.`value-order` ASC SEPARATOR '~'),'~',1) as 'site',
      SUBSTRING_INDEX(GROUP_CONCAT(NULLIF(lbs.dimension, '') ORDER BY lbs.`table-order`,lbs.`value-order` ASC SEPARATOR '~'),'~',1) as 'dimension'
   FROM 
      table1 ad
         LEFT JOIN ( SELECT 
                           t.`parameter` as 'parameter', 
                           v.`value` as 'value',
                           IF(FIND_IN_SET('site',t.attributes),v.site,null) as 'site',
                           IF(FIND_IN_SET('placement',t.attributes),v.placement,null) as 'placement',
                           IF(FIND_IN_SET('format',t.attributes),v.format,null) as 'format',
                           IF(FIND_IN_SET('creative',t.attributes),v.creative,null) as 'creative',
                           IF(FIND_IN_SET('mediaOwner',t.attributes),v.mediaOwner,null) as 'mediaOwner',
                           IF(FIND_IN_SET('targeting',t.attributes),v.targeting,null) as 'targeting',
                           IF(FIND_IN_SET('dimension',t.attributes),v.dimension,null) as 'dimension',
                           t.`order` as 'table-order', 
                           v.`order` as 'value-order' 
                        FROM 
                           table2 t
                              JOIN table3 v 
                                 ON t.tableID = v.tableID
                        WHERE 
                               t.campaignID = 1856
                           AND t.active = 1 
                           AND t.ignore = 0 
                        ORDER BY 
                           t.`order`,
                           v.`order` ) lbs 
            ON ($string)

         LEFT JOIN ( SELECT 
                           cl2.memberid as memberid,
                           cl2.panelid as panelid,
                           COUNT(*) as clicks
                        FROM 
                           table4 cl2 
                        WHERE 
                           1 AND (1) 
                        GROUP BY 
                           cl2.memberid,
                           cl2.panelid ) cl
            ON ad.memberid = cl.memberid
            AND ad.panelid = cl.panelid

         LEFT JOIN table5 st
            ON ad.memberid = st.panelistID
            AND ad.panelid = st.panelID

         JOIN table6 ef
            ON ef.panelID = st.panelID
            AND ef.panelistID = st.panelistID 

   WHERE 
      1 AND (1) 
   GROUP BY 
      ad.memberid, 
      ad.panelid
   ORDER BY 
      ad.memberid ASC, 
      ad.panelid ASC

您显然是想通过您的表名进行通用化,但使用别名可以很好地显示关系。

  1. 您加入基于 ($string) 的子查询别名“lbs”,但没有提供任何可能的上下文/示例——过滤和/或实际加入标准?

  2. 作为“lbs”别名基础的内部选择仅在最终外部查询中使用“site”和“dimension”列...为什么要为所有其他列使用 FIND_IN_SET。

  3. 基于“lbs”查询,您的 table2(t 别名)应该在(campaignID、active、ignore、order)上有一个复合索引,以帮助优化该部分查询和 order by 子句。

  4. 根据您正在查找的“标准”,您的(广告别名)表的最终分组依据/排序依据至少应在 (memberid, panelid) 上有一个复合索引,其中附加列在这些列的前面从您的“广告”表中获取。

  5. 根据您的“WHERE 1 AND (1)”标准,您的(cl2 别名)应在 (memberid, panelid) 加上附加列的前面有一个复合索引,该标准是模棱两可的,只是占位符实际过滤标准。如果没有该示例的真实上下文,我们无法为您提供更好的索引列优化。

  6. “1 AND (1)”的最终 WHERE 子句...与 #5 相同的歧义。

【讨论】:

    猜你喜欢
    • 2011-10-27
    • 1970-01-01
    • 2011-12-15
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 2020-05-16
    • 1970-01-01
    • 2013-02-17
    相关资源
    最近更新 更多