慢依赖子查询 - 如何提高性能?

时间:2011-06-19 17:56:25

标签: php mysql database performance

我的数据库有表名交易,有20000条记录。当我运行此查询时

SELECT T1.* FROM transactions AS T1
WHERE T1.ppno IN 
  (SELECT T2.PPNO FROM transactions AS T2 
   WHERE T2.ppno = T1.ppno 
   HAVING COUNT(T2.ppno) = $doublescount) 
 ORDER BY T1.ppno,T1.numb

至少需要3分钟才能运行。如何加快这个查询?

修改

show create table transactions返回

CREATE TABLE `transactions` (
  `eidx` int(10) unsigned NOT NULL,
  `numb` int(10) unsigned NOT NULL,
  `date` date NOT NULL,
  `time` varchar(45) NOT NULL,
  `name` varchar(45) NOT NULL,
  `add1` varchar(45) NOT NULL,
  `add2` varchar(45) NOT NULL,
  `city` varchar(45) NOT NULL,
  `phno` varchar(45) NOT NULL,
  `nati` varchar(45) NOT NULL,
  `ppno` varchar(45) NOT NULL,
  `cuam` varchar(45) NOT NULL,
  `tcam` varchar(45) NOT NULL,
  `valu` varchar(45) NOT NULL,
  `srch` varchar(45) NOT NULL,
  `stax` varchar(45) NOT NULL,
  `taxp` varchar(45) NOT NULL,
  `roun` varchar(45) NOT NULL,
  `amnt` varchar(45) NOT NULL,
  `encd` varchar(45) NOT NULL,
  `mocd` varchar(45) NOT NULL,
  `endt` varchar(45) NOT NULL,
  `modt` varchar(45) NOT NULL,
  `sflg` varchar(5) NOT NULL,
  `category` varchar(45) NOT NULL DEFAULT 'NA',
  `branch` varchar(10) NOT NULL,
  PRIMARY KEY (`numb`,`branch`,`date`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED

4 个答案:

答案 0 :(得分:5)

答案 1 :(得分:3)

子查询很慢。在包含满足条件的所有ppno的临时表上使用JOIN。

SELECT T1.* FROM transactions AS T1 
JOIN (SELECT DISTINCT T2.PPNO FROM transactions AS T2 HAVING COUNT(T2.ppno) = $doublescount) AS temp ON temp.PPNO=T1.ppno
ORDER BY T1.ppno,T1.numb

答案 2 :(得分:2)

更改SELECT T1.* FROM transactions AS T1,以便它只获取您需要的列,例如SELECT T1.ppno, T1.name FROM transactions as T1,然后使用Gerben提供的连接方法。

当使用SELECT *时,数据库系统必须计算出数据库中的列,然后为每个列和行分配内存 - 在运行查询之前需要进行大量的后台工作。 通过使用命名列,数据库系统只需要检查这些列 - 在运行查询之前减少后台工作。

如果您的查询需要3分钟才能执行,您可能会发生笛卡尔联接,结果集可能会达到数百万。 gerben的join方法通过创建一个包含附加到主表的子查询结果的临时表来防止这种情况,主查询针对此临时表运行以生成更小的结果集。

答案 3 :(得分:0)

如果瓶颈是数据库,您也可以省略ORDER BY并在应用程序而不是数据库中进行排序。