发送数据的时间太长但索引仍然存在

时间:2017-09-13 21:41:32

标签: mysql database indexing

我遇到的查询问题需要20秒才能返回结果:(

在table cases和cases_cstm中,我有960,000行

这是我的查询:

    SELECT  cases.id ,cases_cstm.assunto_c, cases.name , cases.case_number ,
      cases.priority  , accounts.name account_name , 
      accounts.assigned_user_id account_name_owner  , 
      'Accounts' account_name_mod, cases.account_id  , 
      LTRIM(RTRIM(CONCAT(IFNULL(jt1.first_name,''),' ',IFNULL(jt1.last_name,'')))) assigned_user_name , 
      jt1.created_by assigned_user_name_owner  , 
      'Users' assigned_user_name_mod, cases.status , cases.date_entered ,
      cases.assigned_user_id  
   FROM cases  
   LEFT JOIN cases_cstm ON cases.id = cases_cstm.id_c
   LEFT JOIN  accounts accounts ON 
      cases.account_id=accounts.id AND accounts.deleted=0   AND 
      accounts.deleted=0  
   LEFT JOIN  users jt1 ON 
      cases.assigned_user_id=jt1.id AND 
      jt1.deleted=0   AND jt1.deleted=0 
   where 
     (((LTRIM(RTRIM(CONCAT(IFNULL(accounts.name,'')))) LIKE 'rodrigo fernando%' OR 
     LTRIM(RTRIM(CONCAT(IFNULL(accounts.name,'')))) LIKE 'rodrigo fernando%'))) AND 
     cases.deleted=0 ORDER BY cases.date_entered DESC LIMIT 0,11;

这是表格的索引:

+-------+------------+--------------------+--------------+------------------
+-----------+-------------+----------+--------+------+------------+--------
| Table | Non_unique | Key_name           | Seq_in_index | Column_name |Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment 
+-------+------------+--------------------+--------------+------------------
+-----------+-------------+----------+--------+------+------------+---------
| cases |          0 | PRIMARY            |            1 | id          | A         |      911472 |     NULL | NULL   |      | BTREE      |          
| cases |          0 | case_number        |            1 | case_number | A         |      911472 |     NULL | NULL   |      | BTREE      |         
|
| cases |          1 | idx_case_name      |            1 | name        | A         |      911472 |     NULL | NULL   | YES  | BTREE      |         
|
| cases |          1 | idx_account_id     |            1 | account_id  | A         |      455736 |     NULL | NULL   | YES  | BTREE      |         
|
| cases |          1 | idx_cases_stat_del |            1 | assigned_user_id| A         |         106 |     NULL | NULL   | YES  | BTREE      |         
|
| cases |          1 | idx_cases_stat_del |            2 | status      | A         |         197 |     NULL | NULL   | YES  | BTREE      |         
|
| cases |          1 | idx_cases_stat_del |            3 | deleted     | A         |         214 |     NULL | NULL   | YES  | BTREE      |         
|
| cases |          1 | idx_priority       |            1 | priority    | A         |      455736 |     NULL | NULL   | YES  | BTREE      |         
|
| cases |          1 | idx_date_entered   |            1 | date_entered| A         |      455736 |     NULL | NULL   | YES  | BTREE      |         
+-------+------------+--------------------+--------------+------------------
+-----------+-------------+----------+--------+------+------------+---------

The Explain command of query(Image!)

这是查询执行的配置文件:

+--------------------+-----------+
| Status             | Duration  |
+--------------------+-----------+
| starting           |  0.000122 |
| Opening tables     |  0.000180 |
| System lock        |  0.000005 |
| Table lock         |  0.000005 |
| init               |  0.000051 |
| optimizing         |  0.000017 |
| statistics         |  0.000071 |
| preparing          |  0.000021 |
| executing          |  0.000003 |
| Sorting result     |  0.000004 |
| Sending data       | 21.595455 |
| end                |  0.000012 |
| query end          |  0.000002 |
| freeing items      |  0.000419 |
| logging slow query |  0.000005 |
| logging slow query |  0.000002 |
| cleaning up        |  0.000004 |

有人可以帮我解决为什么执行这么长时间的查询吗?

谢谢!

3 个答案:

答案 0 :(得分:0)

您还需要更改查询以及索引。由于您仅对案例表编制了索引,并且您正在使用帐户和用户表,因此在编制索引时也应考虑这些表。在查询中进行如下更改。

SELECT cases.id, cases_cstm.assunto_c, cases.name, cases.case_number, cases.priority, accounts.name account_name, accounts.assigned_user_id account_name_owner, 
'Accounts' account_name_mod, cases.account_id, LTRIM(RTRIM(CONCAT(IFNULL(jt1.first_name,''),' ',IFNULL(jt1.last_name,'')))) assigned_user_name, 
jt1.created_by assigned_user_name_owner,'Users' assigned_user_name_mod, cases.status, cases.date_entered, cases.assigned_user_id 
FROM cases  [enter link description here][1]
LEFT JOIN cases_cstm ON cases.id = cases_cstm.id_c
LEFT JOIN accounts accounts ON cases.account_id=accounts.id AND accounts.deleted=0 AND (TRIM(accounts.name) LIKE 'rodrigo fernando%' OR TRIM(accounts.name) LIKE 'rodrigo fernando%')
LEFT JOIN  users jt1 ON cases.assigned_user_id=jt1.id AND jt1.deleted=0
WHERE cases.deleted=0 ORDER BY cases.date_entered DESC LIMIT 0,11;

然后首先删除未使用的索引,然后在表上创建索引,如下所示:

  1. 案例 - 已删除,date_entered(一个多列索引)
  2. 帐户 - 已删除,名称(包含多列的一个索引)
  3. 用户 - 已删除
  4. 创建这些索引并确保在查询中选择和使用的列序列必须相同,因为MySql使用索引的任何最左前缀。如果您需要更多详细信息,请浏览以下链接:

答案 1 :(得分:0)

首先,将您的LEFT JOIN更改为帐户INNER JOIN我不知道这是否会发生重大变化,但如果您了解其中的差异会更有意义。< / p>

您对LEFT JOIN说的是&#34;我想要所有案例,无论他们是否有相关帐户&#34;。 INNER JOIN在这里表示&#34;给我所有案例并返回所有帐户&#34;。

您的查询的最终结果是相同的,因为您稍后使用WHERE子句过滤掉了内容,但我感觉这可能为{{em> 1}}被忽略了。

第二个可能更大的问题是你的where子句:

idx_account_id

这里有很多功能,MySQL无法使用索引对其进行优化。将检查每个记录的这种情况,并且将为每条记录调用您正在使用的所有功能。这很可能是最大的问题。

首先,这可以简化一下。我认为这个OR语句的两面都是一样的,所以我们先把它变成一个:

 (((LTRIM(RTRIM(CONCAT(IFNULL(accounts.name,'')))) LIKE 'rodrigo fernando%' OR 
 LTRIM(RTRIM(CONCAT(IFNULL(accounts.name,'')))) LIKE 'rodrigo fernando%'))) AND

由于您在switch语句的一侧添加了通配符,为什么还要使用RTRIM呢?

LTRIM(RTRIM(CONCAT(IFNULL(accounts.name,'')))) LIKE 'rodrigo fernando%'

如果只有一件事,你不需要CONCAT任何东西!

LTRIM(CONCAT(IFNULL(accounts.name,''))) LIKE 'rodrigo fernando%'

LTRIM在NULL值上运行良好

LTRIM(IFNULL(accounts.name,'')) LIKE 'rodrigo fernando%'

好吧,这为我们节省了许多功能。但是,最后一个LTRIM仍然是一个主要问题,因为它完全阻止了mysql使用索引。解决方案很简单:

  1. 一次更新您的帐户表:

    更新帐户SET name = LTRIM(name);

  2. 确保无论何时插入新帐户,都要在插入前进行修剪。因此,您现在LTRIM(accounts.name) LIKE 'rodrigo fernando%' 时间内正在执行此操作,而不是INSERT时间。

  3. 将以前的WHERE子句更改为:

    accounts.name LIKE&#39; rodrigo fernando%&#39;

  4. Boom,你现在可以在accounts.name上使用一个索引,它就像他妈的一样快。

答案 2 :(得分:0)

我能够按照Evert的提示解决这个问题! 要清楚,这是一个由系统动态安装的查询,我仍然需要优化代码以删除在这种情况下没有意义的功能。 对于Cases_cstm和帐户案例,有什么帮助我用INNER联接替换LEFT ...只有这个改变才开始在0.9秒内执行查询!

感谢大家的帮助!