Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 摘要联接查询花费的时间太长_Mysql_Aggregate - Fatal编程技术网

Mysql 摘要联接查询花费的时间太长

Mysql 摘要联接查询花费的时间太长,mysql,aggregate,Mysql,Aggregate,我正在尝试获取每个“电话号码”的最大记录,其中process_status='0',为此我使用以下查询 SELECT ID, CUSTID, telephone_number, TOTAL_USAGE, ACCOUNT_STATUS FROM SPRINTABLE_DATA t JOIN (SELECT MAX( id ) AS maxid FROM SPRINTABLE_DATA GROUP BY telephone_number)dt ON t.id = dt.maxid WHERE pro

我正在尝试获取每个“电话号码”的最大记录,其中process_status='0',为此我使用以下查询

SELECT ID, CUSTID, telephone_number, TOTAL_USAGE, ACCOUNT_STATUS
FROM SPRINTABLE_DATA t
JOIN (SELECT MAX( id ) AS maxid FROM SPRINTABLE_DATA GROUP BY telephone_number)dt
ON t.id = dt.maxid WHERE process_status = '0'
AND RESET_FLAG = '0'
ORDER BY id DESC limit 0,700
上面的查询给了我想要的结果,但问题是这太慢了

我的表大约有2000万行,这个查询有时需要15-20分钟

可以做些什么来改善这一点

这是结构:

CREATE TABLE `SPRINTABLE_DATA` (
 `ID` bigint(11) NOT NULL AUTO_INCREMENT,
 `CUSTID` int(11) DEFAULT NULL,
 `telephone_number` varchar(20) DEFAULT NULL,
 `TOTAL_USAGE` int(11) DEFAULT NULL,
 `PROCESS_STATUS` tinyint(4) DEFAULT '0',
 `RESET_FLAG` tinyint(4) DEFAULT '0',
 `RESET_REASON` varchar(10) DEFAULT NULL,
 `PLAN_ID` varchar(20) DEFAULT NULL,
 `ACCOUNT_STATUS` varchar(30) DEFAULT NULL,
 PRIMARY KEY (`ID`),
 KEY `telephone_number` (`telephone_number`),
 KEY `CALL_CUST` (`CALL_START_TIME`,`CUSTID`),
 KEY `telephone_number1` (`telephone_number `,`PROCESS_STATUS`,`SOC_ADDED`),
 KEY `CURRENT_USAGE` (`CURRENT_USAGE`),
 KEY `TOTAL_USAGE` (`TOTAL_USAGE`)
) ENGINE=InnoDB AUTO_INCREMENT=36392272 DEFAULT CHARSET=latin1

对您的查询做了轻微修改

  SELECT ID, CUSTID, telephone_number, TOTAL_USAGE, ACCOUNT_STATUS
    FROM SPRINTABLE_DATA t
    JOIN (SELECT telephone_number,MAX( id ) AS maxid FROM SPRINTABLE_DATA GROUP BY telephone_number)dt
    ON t.id = dt.maxid WHERE process_status = '0'
    AND RESET_FLAG = '0'
    ORDER BY id DESC limit 0,700
如果还没有,请添加这些索引

ALTER TABLE SPRINTABLE_DATA  ADD KEY (telephone_number,id)
ALTER TABLE SPRINTABLE_DATA  ADD KEY (process_status,reset_flag,id)
另一个可能最快的选择是使用相关子查询

  SELECT ID, CUSTID, telephone_number, TOTAL_USAGE, ACCOUNT_STATUS
    FROM SPRINTABLE_DATA t WHERE EXISTS
   (SELECT MAX( id )  FROM SPRINTABLE_DATA tt WHERE t.id=tt.id AND tt.process_status = '0'
    AND tt.RESET_FLAG = '0'   )     
    ORDER BY id DESC limit 0,700
为此你需要

ALTER TABLE SPRINTABLE_DATA  ADD KEY (id,process_status,reset_flag)
SELECT q.ID   /* get our 700 records */
  FROM SPRINTABLE_DATA q
  JOIN (
          SELECT MAX( id ) AS id 
           FROM SPRINTABLE_DATA  
       GROUP BY telephone_number
       ) r ON q.id = r.id
  WHERE q.process_status = '0'
    AND q.RESET_FLAG = '0'
  ORDER BY q.ID DESC
  LIMIT 0,700

您似乎正在寻找最近拨打的700个号码。(如果不正确,请编辑您的问题

您的查询遵循一个很好的做法,在子查询中检索每个项目的最新日志行(在您的情况下是电话号码),如下所示

   SELECT MAX( id ) AS id 
    FROM SPRINTABLE_DATA  
GROUP BY telephone_number
要优化此子查询的性能,您需要在两个字段上按顺序使用复合索引:
(电话号码,id)
。如果您没有该索引,请将其添加进去。这是为了允许所谓的松散索引扫描,这是一种非常有效的满足查询的方法

第二,你在寻找(我猜)数据的一小部分。大概您有超过700个不同的
电话号码
值。这意味着您正在按顺序对大量数据进行排序,但只会有限制地将其丢弃。因此,让我们执行延迟联接,对最少数量的列进行排序,然后检索您需要的所有信息

下面是如何获取所需700行的ID值

ALTER TABLE SPRINTABLE_DATA  ADD KEY (id,process_status,reset_flag)
SELECT q.ID   /* get our 700 records */
  FROM SPRINTABLE_DATA q
  JOIN (
          SELECT MAX( id ) AS id 
           FROM SPRINTABLE_DATA  
       GROUP BY telephone_number
       ) r ON q.id = r.id
  WHERE q.process_status = '0'
    AND q.RESET_FLAG = '0'
  ORDER BY q.ID DESC
  LIMIT 0,700
这将提取700个id号。您需要对索引进行一些实验,以找出最有助于优化此功能的方法。有可能

   process_status, RESET_FLAG, id
   reset_flag, process_status, telephone_number, ID
将有帮助。更改索引中列的顺序也可能有帮助,如下所示:

   id, process_status, RESET_FLAG
                    SELECT MAX( id ) AS id  /* 700 matching numbers */
                     FROM SPRINTABLE_DATA  
                    WHERE process_status = '0'
                      AND reset_flag = '0'
                 GROUP BY telephone_number
                 ORDER BY ID desc
                    LIMIT 0,700
两个都试试

最后,我们将使用它作为子查询来执行连接(所谓的延迟连接)以获取实际的细节记录。这种技术不需要对所有数据进行排序

SELECT t.ID, t.CUSTID, t.telephone_number, t.TOTAL_USAGE, t.ACCOUNT_STATUS
  FROM SPRINTABLE_DATA t
  JOIN (
          SELECT q.ID  /* get our 700 records */
            FROM SPRINTABLE_DATA q
            JOIN (
                    SELECT MAX( id ) AS id 
                     FROM SPRINTABLE_DATA  
                 GROUP BY telephone_number
                 ) r ON q.id = r.id
            WHERE q.process_status = '0'
              AND q.RESET_FLAG = '0'
            ORDER BY q.ID DESC
            LIMIT 0,700
       ) s ON t.ID = s.ID
  ORDER BY t.ID DESC
这将产生相同的结果,但会更快

最后,如果可以从符合条件的700个号码中选择最新的呼叫,则可以大大简化此查询。不过,这将以微妙的方式更改结果集。在这种情况下,呼叫选择子查询将如下所示:

   id, process_status, RESET_FLAG
                    SELECT MAX( id ) AS id  /* 700 matching numbers */
                     FROM SPRINTABLE_DATA  
                    WHERE process_status = '0'
                      AND reset_flag = '0'
                 GROUP BY telephone_number
                 ORDER BY ID desc
                    LIMIT 0,700
使用复合覆盖索引

   process_status, RESET_FLAG, id
   reset_flag, process_status, telephone_number, ID
此查询将非常快。在这种情况下,您的最终查询将是

SELECT t.ID, t.CUSTID, t.telephone_number, t.TOTAL_USAGE, t.ACCOUNT_STATUS
  FROM SPRINTABLE_DATA t
  JOIN (
                    SELECT MAX( id ) AS id  /* 700 matching numbers */
                     FROM SPRINTABLE_DATA  
                    WHERE process_status = '0'
                      AND reset_flag = '0'
                 GROUP BY telephone_number
                 ORDER BY ID desc
                    LIMIT 0,700
       ) s ON t.ID = s.ID
  ORDER BY t.ID DESC

表定义会有帮助的对不起!但是我不能提供整个表的定义,但我可以根据需要提供其中的一些。我在DBs方面没有太多的专业知识,但我的第一个猜测是group by。您在
电话号码
字段中有任何索引吗?@Mihai不是要表的内容,而是要
的输出SHOW CREATE TABLE SPRINTABLE_DATA
。为什么不能提供整个表定义?如果不知道您在做什么,将很难提供帮助!第一个键的列的顺序错误,无法优化子查询。@OllieJones确定吗?
选择电话号码MAX(id)由于SPRINTABLE_DATA GROUP BY telephone_number
中的maxid将使用第一个索引。MAX,然后GROUP BYYes,我确定。它是按电话号码分组,然后在每个组中查找MAX id。这被称为松散索引扫描。@OllieJones&Mihai-那么,结果如何,我是否应继续使用上面提供的解决方案??@Tarun编辑,j请运行这两条语句。