MySql - 进一步查询优化SELECT WHERE IN

时间:2016-02-21 12:18:37

标签: mysql sql database optimization query-optimization

我目前正在处理财务申请。一个包含8列的MYSql数据库。 1百万条记录。

  

插入:每分钟30行   更新:0。
  选择:一个查询   每200ms运行一次。返回大约200,000条记录   每次执行。

选择查询,如下所示:

SELECT COLUMNB, COLUMNC, COLUMND, COLUMNE FROM TABLE
WHERE COLUMNE IN('ABCD','EFGH','IJKL','MNOP')
ORDER BY COLUMNB DESC

我的回复时间如下:执行:0.903秒获取:0.2秒。

  

总计~1.1秒

当我做一个解释时,我得到以下内容:

  

id,select_type,table,partitions,type,possible_keys,key,key_len,   ref,rows,filtered,Extra'1','SIMPLE','table',NULL,'ALL',   'tbl_ColumnE_ColumnB,tbl_ColumnE',NULL,NULL,   NULL,'1180834','34 .33','使用where;使用filesort'

INDEXES已经有效:

  1. tbl_ColumnE_ColumnB,
  2. tbl_ColumnB_ColumnE,
  3. tbl_ColumnE
  4. tbl_ColumnB
  5. 因为这是一个基于金融股票市场的应用程序。我需要将总执行时间进一步降低到接近200毫秒或尽可能小。有什么我可以改进的吗?

    已经完成:

    1. innodb_buffer_pool从8M增加到2000M(节省30%)
    2. 将OR运算符更改为IN运算符(之前为OR。保存20%)
    3. 显示创建表:

      CREATE TABLE `tbl` (
          `id` int(11) NOT NULL AUTO_INCREMENT, 
          `COLUMNB` timestamp NULL DEFAULT NULL, 
          `COLUMNC` decimal(20,10) DEFAULT NULL, 
          `COLUMND` decimal(20,10) DEFAULT NULL, 
          `COLUMNX` decimal(20,10) DEFAULT NULL, 
          `COLUMNY` decimal(20,10) DEFAULT NULL, 
          `COLUMNZ` decimal(20,10) DEFAULT NULL, 
          `COLUMNE` varchar(45) DEFAULT NULL, 
          `COLUMNF` int(11) DEFAULT NULL, 
          PRIMARY KEY (`id`), 
          UNIQUE KEY `id_UNIQUE` (`id`), 
          KEY `tbl_ColumnE_ColumnB` (`ColumnE`,`ColumnB`), 
          KEY `tbl_ColumnB_ColumnE` (`ColumnB`,`ColumnE`), 
          KEY `tbl_ColumnB` (`ColumnB`), 
          KEY `tbl_ColumnE` (`ColumnE`)
      ) ENGINE=InnoDB AUTO_INCREMENT=1718507 DEFAULT CHARSET=utf8'
      

3 个答案:

答案 0 :(得分:0)

此查询:

SELECT COLUMNB, COLUMNC, COLUMND, COLUMNE
FROM TABLE
WHERE COLUMNE IN ('ABCD', 'EFGH', 'IJKL', 'MNOP')
ORDER BY COLUMNB DESC;

没有方便的优化方法。问题是INORDER BY。对于IN列表中的单个值,最佳索引可能是(COLUMNE, COLUMNB, COLUMNC, COLUMND)(在MySQL中降序排列可能很棘手)。

如果IN列表中的四个值是常量,我建议更改数据结构,使它们在一列中。然后这个查询:

SELECT COLUMNB, COLUMNC, COLUMND, COLUMNE
FROM TABLE
WHERE COLUMNEPRIME = 'ABCDEFGHIJKLMNOP'
ORDER BY COLUMNB DESC;

可以利用(COLUMNEPRIME, COLUMNB, COLUMNC, COLUMND, COLUMNE)上的索引。唉,在MySQL中,可能需要使用一个会减慢插入速度的触发器。

如果获取速度如此之快,您可能会发现在应用程序而不是数据库中排序更快。因此,请尝试查询:

SELECT COLUMNB, COLUMNC, COLUMND, COLUMNE
FROM TABLE
WHERE COLUMNE IN ('ABCD', 'EFGH', 'IJKL', 'MNOP');

使用四部分复合索引。

我注意到,对于大多数用途来说,每秒多次返回20%的表似乎是不必要的。也许有更好的方法来设计整个系统来做你需要的。

答案 1 :(得分:0)

试试这个。你在COLUMNE有多少种不同的数据?如果不是这样,你也可以使用ENUM来加速查询。 您还可以使用客户端中的compress选项来最小化数据传输。

CREATE TEMPORARY TABLE `tbls` (
  `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  `val` VARCHAR(45) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `val` (`val`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

INSERT INTO tbls (val) VALUES('ABCD'),('EFGH'),('IJKL'),('MNOP');

EXPLAIN
 SELECT COLUMNB, COLUMNC, COLUMND, COLUMNE FROM tbl
 INNER JOIN tbls ON tbl.COLUMNE = tbls.val
 ORDER BY COLUMNB DESC;

答案 2 :(得分:0)

与IN匹配的行的百分比是多少?如果它超过20%,优化器将避开索引(从E开始),因为扫描整个表可能会更快。

需要Sort(“filesort”),因为无法以正确的顺序获取行。您可以尝试FORCE INDEX(ColumnB)

来试验这一点

查询花费这么长时间的部分原因是您返回200K行。思考你是否可以避免这种情况。

但等等!如果你每2秒只插入一行,为什么你觉得0.2秒后会有什么变化?当您插入一行时,触发重新计算(此连接必须在应用程序中完成,不能完全在sql中完成)。这将导致更快的响应,因为您不会在下一次计算时等待0.2秒。