简体   繁体   English

没有where子句的M​​ySQL查询运行非常慢(实际上从不提供输出)

[英]MySql query runs very slow(actually never gives output) without where clause

I have a mysql query and it works fine when i use where clause, but when i donot use where clause it gone and never gives the output and finally timeout. 我有一个mysql查询,当我使用where子句时它运行良好,但是当我不使用where子句时,它消失了,并且从不给出输出,最后也没有超时。 Actually i have used Explain command to check the performance of the query and in both cases the Explain gives the same number of rows used in joining. 实际上,我已经使用Explain命令检查查询的性能,并且在两种情况下, Explain给出的连接使用的行数均相同。 I have attached the image of output got with Explain command. 我已经附上了Explain命令获得的输出图像。 Below is the query. 下面是查询。 I couldn't figure whats the problem here. 我不知道这里出了什么问题。 Any help is highly appreciated. 非常感谢您的帮助。 Thanks. 谢谢。

 SELECT 
        MCI.CLIENT_ID AS CLIENT_ID, MCI.NAME AS CLIENT_NAME, MCI.PRIMARY_CONTACT AS CLIENT_PRIMARY_CONTACT, 
        MCI.ADDED_BY AS SP_ID, CONCAT(MUD_SP.FIRST_NAME, ' ', MUD_SP.LAST_NAME) AS SP_NAME, 
        MCI.FK_PROSPECT_ID AS PROSPECT_ID, MCI.DATE_ADDED AS ADDED_ON,
        (SELECT GROUP_CONCAT(LT.TAG_TEXT SEPARATOR ', ') 
            FROM LK_TAG LT
            INNER JOIN M_OBJECT_TAG_MAPPING MOTM
            ON LT.PK_ID = MOTM.FK_TAG_ID
            WHERE MOTM.FK_OBJECT_ID = MCI.FK_PROSPECT_ID
                AND MOTM.OBJECT_TYPE = 1
                AND MOTM.IS_ACTIVE = 1
        ) AS TAGS,
        IFNULL(SUM(GET_DIGITS(MMR.RCP_AMOUNT)), 0) AS REVENUE_SO_FAR,
        IFNULL(SUM(GET_DIGITS(MMR.RCP_RUPEES)), 0) AS REVENUE_INR,
        COUNT(DISTINCT PMI_MONTHLY.PROJECT_ID) AS MONTHLY,
        COUNT(DISTINCT PMI_FIXED.PROJECT_ID) AS FIXED,
        COUNT(DISTINCT PMI_HOURLY.PROJECT_ID) AS HOURLY,
        COUNT(DISTINCT PMI_ANNUAL.PROJECT_ID) AS ANNUAL,
        COUNT(DISTINCT PMI_CURRENTLY_RUNNING.PROJECT_ID) AS CURRENTLY_RUNNING_PROJECTS,
        COUNT(DISTINCT PMI_YET_TO_START.PROJECT_ID) AS YET_TO_START_PROJECTS,
        COUNT(DISTINCT PMI_TECH_SALES_CLOSED.PROJECT_ID) AS TECH_SALES_CLOSED_PROJECTS
    FROM 
        M_CLIENT_INFO MCI
        INNER JOIN M_USER_DETAILS MUD_SP
            ON MCI.ADDED_BY = MUD_SP.PK_ID
        LEFT OUTER JOIN M_MONTH_RECEIPT MMR
                ON MMR.CLIENT_ID = MCI.CLIENT_ID
        LEFT OUTER JOIN M_PROJECT_INFO PMI_FIXED
                ON PMI_FIXED.CLIENT_ID =  MCI.CLIENT_ID AND PMI_FIXED.PROJECT_TYPE = 1
        LEFT OUTER JOIN M_PROJECT_INFO PMI_MONTHLY
                ON PMI_MONTHLY.CLIENT_ID =  MCI.CLIENT_ID AND PMI_MONTHLY.PROJECT_TYPE = 2
        LEFT OUTER JOIN M_PROJECT_INFO PMI_HOURLY
                ON PMI_HOURLY.CLIENT_ID =  MCI.CLIENT_ID AND PMI_HOURLY.PROJECT_TYPE = 3
        LEFT OUTER JOIN M_PROJECT_INFO PMI_ANNUAL
                ON PMI_ANNUAL.CLIENT_ID =  MCI.CLIENT_ID AND PMI_ANNUAL.PROJECT_TYPE = 4
        LEFT OUTER JOIN M_PROJECT_INFO PMI_CURRENTLY_RUNNING
                ON PMI_CURRENTLY_RUNNING.CLIENT_ID =  MCI.CLIENT_ID AND PMI_CURRENTLY_RUNNING.STATUS = 4
        LEFT OUTER JOIN M_PROJECT_INFO PMI_YET_TO_START
                ON PMI_YET_TO_START.CLIENT_ID =  MCI.CLIENT_ID AND PMI_YET_TO_START.STATUS < 4
        LEFT OUTER JOIN M_PROJECT_INFO PMI_TECH_SALES_CLOSED
                ON PMI_TECH_SALES_CLOSED.CLIENT_ID =  MCI.CLIENT_ID AND PMI_TECH_SALES_CLOSED.STATUS > 4
               WHERE YEAR(MCI.DATE_ADDED) = '2012'
                GROUP BY MCI.CLIENT_ID ORDER BY CLIENT_NAME ASC  

在此处输入图片说明

Yes, as many people have said, the key is that when you have the where clause, mysql engine filters the table M_CLIENT_INFO --probably drammatically--. 是的,正如许多人所说的,关键是当您拥有where子句时,mysql引擎会过滤表M_CLIENT_INFO -可能是动态地-。

A similar result as removing the where clause is to to add this where clause: 与删除where子句类似的结果是添加以下where子句:

where 1 = 1

You will see that the performance is degraded also because mysql will try to get all the data. 您还会看到性能下降,因为mysql会尝试获取所有数据。

Remove the where clause and all columns from select and add a count to see how many records you get. 从select中删除where子句和所有列,并添加计数以查看获得的记录数。 If it is reasonable, say up to 10k, then do the following, 如果合理,最多说10k,然后执行以下操作,

  1. put back the select columns related to M_CLIENT_INFO 放回与M_CLIENT_INFO相关的选择列

  2. do not include the nested one "TAGS" 不包括嵌套的一个“ TAGS”

  3. remove all your joins 删除所有联接

  4. run your query without where clause and gradually include the joins 在不使用where子句的情况下运行查询,并逐渐包含联接

this way you'll find out when the timeout is caused. 这样,您就可以找出造成超时的时间。

I would try the following. 我会尝试以下。 First, MySQL has a keyword "STRAIGHT_JOIN" which tells the optimizer to do the query in the table order you've specified. 首先,MySQL有一个关键字“ STRAIGHT_JOIN”,它告诉优化器按照您指定的表顺序进行查询。 Since all you left-joins are child-related (like a lookup table), you don't want MySQL to try and interpret one of those as a primary basis of the query. 由于所有左联接都是与子相关的(例如查找表),因此您不希望MySQL尝试将其中之一解释为查询的主要基础。

SELECT STRAIGHT_JOIN ... rest of query. SELECT STRAIGHT_JOIN ...其余查询。

Next, your M_PROJECT_INFO table, I dont know how many columns of data are out there, but you appear to be concentrating on just a few columns on your DISTINCT aggregates. 接下来,您的M_PROJECT_INFO表不知道有多少数据列,但是您似乎只专注于DISTINCT聚合中的几列。 I would make sure you have a covering index on these elements to help the query via an index on 我将确保您在这些元素上具有覆盖索引,以通过以下索引来帮助查询

( Client_ID, Project_Type, Status, Project_ID ) (Client_ID,Project_Type,Status,Project_ID)

This way the engine can apply the criteria and get the distinct all out of the index instead of having to go back to the raw data pages for the query. 这样,引擎可以应用条件并从索引中获取唯一的内容,而不必回到原始数据页面进行查询。

Third, your M_CLIENT_INFO table. 第三,您的M_CLIENT_INFO表。 Ensure that has an index on both your criteria, group by AND your Order By, and change your order by from the aliased "CLIENT_NAME" to the actual column of the SQL table so it matches the index 确保在两个条件上都有一个索引,并按AND和Order By进行分组,并通过别名“ CLIENT_NAME”将订单更改为SQL表的实际列,以使其与索引匹配

( Date_Added, Client_ID, Name ) (添加日期,客户ID, Name

I have "name" in ticks as it is also a reserved word and helps clarify the column, not the keyword. 我在“滴答”中有一个“名称”,因为它也是一个保留字,可以帮助澄清该列,而不是关键字。

Next, the WHERE clause. 接下来,WHERE子句。 Whenever you apply a function to an indexed column name, it doesn't work the greatest, especially on date/time fields... You might want to change your where clause to 每当将函数应用于索引列名时,它都无法发挥最大的作用,尤其是在日期/时间字段上……您可能需要将where子句更改为

WHERE MCI.Date_Added between '2012-01-01' and '2012-12-31 23:59:59' WHERE MCI.Date_在“ 2012-01-01”和“ 2012-12-31 23:59:59”之间添加

so the BETWEEN range is showing the entire year and the index can better be utilized. 因此BETWEEN范围会显示整个年份,因此可以更好地利用该指数。

Finally, if the above do not help, I would consider splitting your query some. 最后,如果上述方法没有帮助,我会考虑将您的查询拆分一些。 The GROUP_CONCACT inline select for the TAGS might be a bit of a killer for you. TAGS的GROUP_CONCACT内联选择可能对您来说是个杀手er。 You might want to have all the distinct elements first for the grouping per client, THEN get those details.... Something like 您可能希望首先将所有不同的元素用于每个客户的分组,然后获取这些详细信息。

select
      PQ.*,
      group_concat(...) tags
   from
      ( the entire primary part of the query ) as PQ
         Left join yourGroupConcatTableBasis on key columns

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM