Mysql查询性能很慢

时间:2018-03-28 13:49:42

标签: mysql performance query-performance

以下查询处理时间超过8分钟,处理了900,000行。它非常慢,影响我的产品。我无法确定为什么查询变慢,所有索引都设置得很好。

explain SELECT 
    COUNT(DISTINCT (cinfo.CONTACT_ID))
FROM
    cinfo
        INNER JOIN
    LTocMapping ON cinfo.CONTACT_ID = LTocMapping.CONTACT_ID
WHERE
    (((((((((cinfo.COUNTRY LIKE '%Panama%')
        OR (cinfo.COUNTRY LIKE '%PANAMA%'))
        AND (((cinfo.CONTACT_EMAIL NOT LIKE '%test%')
        AND (cinfo.CONTACT_EMAIL NOT LIKE '%engine%'))
        OR (cinfo.CONTACT_EMAIL IS NULL)))
        AND ((SELECT 
            (GROUP_CONCAT(Temp.LIST_ID
                    ORDER BY Temp.LIST_ID) REGEXP ('.*,*221715000514445053,*.*$'))
            FROM
                LTocMapping Temp
            WHERE
                ((LTocMapping.CONTACT_ID = Temp.CONTACT_ID)
                    AND (((Temp.MAPPING_ID >= 221715000000000000)
                    AND (Temp.MAPPING_ID <= 221715999999999999))
                    OR ((Temp.MAPPING_ID >= 0)
                    AND (Temp.MAPPING_ID <= 999999999999))))
            GROUP BY Temp.CONTACT_ID) = '0'))
        AND ((SELECT 
            (GROUP_CONCAT(Temp.LIST_ID
                    ORDER BY Temp.LIST_ID) REGEXP ('.*,*221715000520574130,*.*$'))
            FROM
                LTocMapping Temp
            WHERE
                ((LTocMapping.CONTACT_ID = Temp.CONTACT_ID)
                    AND (((Temp.MAPPING_ID >= 221715000000000000)
                    AND (Temp.MAPPING_ID <= 221715999999999999))
                    OR ((Temp.MAPPING_ID >= 0)
                    AND (Temp.MAPPING_ID <= 999999999999))))
            GROUP BY Temp.CONTACT_ID) = '0'))
        AND (LTocMapping.LIST_ID IN (221715000520574130 , 221715000201569885)))
        AND (LTocMapping.STATUS = BINARY 'subscribed'))
        AND (((cinfo.CONTACT_STATUS = BINARY 'active')
        OR (cinfo.CONTACT_STATUS = BINARY 'softbounce'))
        AND (LTocMapping.STATUS = BINARY 'subscribed')))
        AND (((cinfo.CONTACT_ID >= 221715000000000000)
        AND (cinfo.CONTACT_ID <= 221715999999999999))
        OR ((cinfo.CONTACT_ID >= 0)
        AND (cinfo.CONTACT_ID <= 999999999999))))

答案是

enter image description here

下表FYR

表1:

mysql> desc cinfo;
+------------------------+--------------+------+-----+-----------+-------+
| Field                  | Type         | Null | Key | Default   | Extra |
+------------------------+--------------+------+-----+-----------+-------+
| CONTACT_ID             | bigint(19)   | NO   | PRI | NULL      |       |
| CONTACT_EMAIL          | varchar(100) | NO   | MUL | NULL      |       |
| TITLE                  | varchar(20)  | YES  |     | NULL      |       |
| FIRSTNAME              | varchar(100) | YES  |     | NULL      |       |
| LASTNAME               | varchar(50)  | YES  |     | NULL      |       |     |
| ADDED_BY               | varchar(20)  | YES  |     | NULL      |       |
| ADDED_TIME             | bigint(19)   | NO   |     | NULL      |       |
| LAST_UPDATED_TIME      | bigint(19)   | NO   |     | NULL      |       |
+------------------------+--------------+------+-----+-----------+-------+

表2:

 mysql> desc LTocMapping;
+---------------------+--------------+------+-----+------------+-------+
| Field               | Type         | Null | Key | Default    | Extra |
+---------------------+--------------+------+-----+------------+-------+
| MAPPING_ID          | bigint(19)   | NO   | PRI | NULL       |       |
| CONTACT_ID          | bigint(19)   | NO   | MUL | NULL       |       |
| LIST_ID             | bigint(19)   | NO   | MUL | NULL       |       |
| STATUS              | varchar(100) | YES  |     | subscribed |       |
| MAPPING_STATUS      | varchar(20)  | YES  |     | connected  |       |
| MAPPING_TIME        | bigint(19)   | YES  |     | NULL       |       |
+---------------------+--------------+------+-----+------------+-------+

2 个答案:

答案 0 :(得分:0)

据我所知,你的子查询是瓶颈:

  • 对于第一个子查询,您使用的是LTocMapping.CONTACT_ID
  • 对于第二个子查询,您也使用LTocMapping.CONTACT_ID

这些引用(对外部查询的值)导致这些内部查询变为correlated subqueries(也称为dependent subqueries)。这意味着:对于要在其中一个外部表(~970000)上获取的每一行 - 您在另一个表上触发了另外两个查询。

那么,你正在执行的查询是180万(看起来也不是微不足道)。

大多数情况下,相关的子查询可以由适当的连接替换。但这取决于用例。当使用不同的别名时,您也可以两次加入同一个表。

但是为了概述一些连接选项,你需要解释为什么导致条件group_concat(....) = '0'的子查询很重要 - 或者更好,你想要实现的目标。

(ps。:您还可以看到,explain将其概述为dependent subquery

答案 1 :(得分:0)

OR效率低下,看看你是否可以避免它。

LIKE中的前导通配符效率低下。查看FULLTEXT索引是否适合您。

使用适当的COLLATION,您无需同时测试大写和小写。您也可以避免使用BINARY。在这两种情况下,您都可以使用索引。 (你有什么指数?)

尝试从

更改
WHERE ( ( SELECT ... ) = '0' )

WHERE ( NOT EXISTS ( SELECT ... ) )

SELECT需要进行一些修改。)

(请摆脱一些冗余的问题;很难阅读。)

(请使用SHOW CREATE TABLE;它比DESCRIBE更具描述性。)