Mysql选择 - 提高性能

时间:2010-06-09 18:45:59

标签: mysql performance between

我正在开设一家只通过贷款销售产品的电子商店。我在任何类别中每页显示10个产品,每个产品有3个不同的价格标签 - 3种不同的贷款类型。在测试时间一切都很顺利,查询执行时间很完美,但今天将更改转移到生产服务器时,网站在大约2分钟内“崩溃”。用于选择贷款类型的查询有时会挂起约10秒,并且经常发生,因此无法跟上并且 hella slow 。用于存储数据的表有大约2百万条记录,每个选择看起来像这样:

SELECT * 
FROM products_loans 
WHERE KOD IN("X17/Q30-10", "X17/12", "X17/5-24") 
AND 369.27 BETWEEN CENA_OD AND CENA_DO;

3种贷款类型和需要在CENA_OD和CENA_DO之间的价格,因此返回3行。

但是由于我需要每页显示10个产品,我需要使用 OR 通过修改后的选择运行它,因为我没有找到任何其他解决方案。我问过它here,但没有回答。正如引用文章中所提到的,这必须单独完成,因为没有列可以在连接中使用(当然价格和代码除外,但结果非常非常糟糕)。以下是通过INDEX索引的show create table,kod和CENA_OD / CENA_DO。

CREATE TABLE `products_loans` (
  `KOEF_ID` bigint(20) NOT NULL,
  `KOD` varchar(30) NOT NULL,
  `AKONTACIA` int(11) NOT NULL,
  `POCET_SPLATOK` int(11) NOT NULL,
  `koeficient` decimal(10,2) NOT NULL default '0.00',
  `CENA_OD` decimal(10,2) default NULL,
  `CENA_DO` decimal(10,2) default NULL,
  `PREDAJNA_CENA` decimal(10,2) default NULL,
  `AKONTACIA_SUMA` decimal(10,2) default NULL,
  `TYP_VYHODY` varchar(4) default NULL,
  `stage` smallint(6) NOT NULL default '1',
 PRIMARY KEY  (`KOEF_ID`),
 KEY `CENA_OD` (`CENA_OD`),
 KEY `CENA_DO` (`CENA_DO`),
 KEY `KOD` (`KOD`),
 KEY `stage` (`stage`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

并选择所有贷款类型,然后通过php过滤它们并不好用,因为每种类型都有超过50k的记录,而选择也花费太多时间......

任何提高速度的想法都值得赞赏。

编辑:

这是解释

+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+
| id | select_type | table          | type  | possible_keys       | key  | key_len | ref  | rows   | Extra       |
+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | products_loans | range | CENA_OD,CENA_DO,KOD | KOD  | 92      | NULL | 190158 | Using where |
+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+

我已经尝试了组合索引,它将测试服务器的性能从0.44秒提高到0.06秒,但是我无法从家里访问生产服务器,所以明天我将不得不尝试。

3 个答案:

答案 0 :(得分:2)

您的问题是您正在搜索包含点的间隔(而不是间隔中所有点的更常规查询)。这些查询与标准B树索引不兼容,因此您需要使用R-Tree索引。不幸的是,MySQL不允许您在列上选择R-Tree索引,但是您可以通过将列类型更改为GEOMETRY并使用几何函数来检查间隔是否包含该点来获得所需的索引。

请参阅Quassnoi的文章Adjacency list vs. nested sets: MySQL,在那里他会更详细地解释这一点。用例不同,但所涉及的技术是相同的。以下是本文相关部分的摘录:

  

还有一类任务需要搜索包含已知值的所有范围:

     
      
  • 在IP范围禁令列表中搜索IP地址
  •   
  • 在日期范围内搜索指定日期
  •   
     

和其他几个人。使用MySQL的R-Tree功能可以改善这些任务。

答案 1 :(得分:1)

尝试重构您的查询,如:

SELECT * FROM products_loans 
WHERE KOD IN("X17/Q30-10", "X17/12", "X17/5-24") 
AND CENA_OD >= 369.27
AND CENA_DO <= 369.27;

(选择索引时mysql不是很聪明)并检查性能。

下一个尝试是添加组合键 - (KOD,CENA_OD,CENA_DO)

接下来的主要尝试是重构你的基地,让产品与价格分开。这应该真的有帮助。

PS:你也可以迁移到postgresql,它在选择正确的索引时比mysql更聪明。

答案 2 :(得分:0)

MySQL只能使用1个密钥。如果您始终通过3列获得条目,则根据列中的实际数据(范围),以下其中一项可以很好地添加大量性能:

ALTER TABLE products_loans ADD INDEX(KOD, CENA_OD, CENA_DO);
ALTER TABLE products_loans ADD INDEX(CENA_OD, CENA_DO, KOD);

请注意,列的顺序很重要!如果这不能提高性能,请向我们提供查询的EXPLAIN输出。