使用索引在mysql中进行整数比较

时间:2010-06-24 09:34:21

标签: sql mysql performance indexing

我需要比较mysql表中的整数。非常简单,但这个表格相当大......所以查询需要 很长时间 。没问题,我可以使用索引。根据{{​​3}},我应该能够使用比较运算符的索引: “B树索引可用于使用=,>,> =,<,< =或BETWEEN”

的表达式中的列比较

然而,当我尝试这个时它对性能没有影响,并且根据解释不使用索引:(

SELECT * FROM Node n WHERE n.X < 800000

这会导致性能极差,并且调用explain会将我们的“Rectangle_Index”显示为possible_keys,但实际上使用了NULL键...这里是create table语句:

CREATE TABLE `Visual_Node` (
  `Id` bigint(20) NOT NULL AUTO_INCREMENT,
  `X` bigint(20) NOT NULL,
  `Y` bigint(20) NOT NULL,
  `X_plus_Width` bigint(20) DEFAULT NULL,
  `Y_plus_Height` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`Id`),
  KEY `Rectangle_Index` (`X`,`X_plus_Width`,`Y`,`Y_plus_Height`)
) ENGINE=InnoDB AUTO_INCREMENT=4340743 DEFAULT CHARSET=latin1

任何人都可以帮助此查询吗?我想要运行的实际查询如下:

SELECT * FROM Node n WHERE 800000 BETWEEN n.X and n.X_plus_Width AND 1234567 BETWEEN n.Y and n.Y_plus_Height

更新(在下面的一个答案中提到) 下面是基本查询的解释输出: 改变表结构对我来说非常困难。这是我的解释的输出:

mysql> explain select * from Node n where n.X < 800000;     
+----+-------------+-------+------+-----------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys   | key  | key_len | ref  | rows   | Extra       |
+----+-------------+-------+------+-----------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | n     | ALL  | Rectangle_Index | NULL | NULL    | NULL | 173952 | Using where | 
+----+-------------+-------+------+-----------------+------+---------+------+--------+-------------+
1 row in set (0.02 sec)

3 个答案:

答案 0 :(得分:3)

如果您将查询重写为

SELECT * 
FROM Node n 
WHERE 
  n.X <= 800000  AND 
  n.X_plus_Width >= 800000  AND 
  n.Y <= 1234567  AND
  n.Y_plus_Height >= 1234567

Mysql可以使用索引作为一列(它不能使用索引超过1个范围的条件,你有4个。

我建议你看看Spatial extensions

答案 1 :(得分:2)

您是否检查了多列索引的详细信息 - 特别是有关优化程序如何(或不能)使用它们的部分。以下是this页面的引用:

  

如果表格有多列   index,任何最左边的前缀   index可以由优化器使用   找到行。例如,如果你有   三列索引(col1,col2,   col3),你有索引搜索   (col1),(col1,col2)上的功能,   和(col1,col2,col3)。

也许您可以尝试创建多个单列索引,而不是一个多列索引?

编辑1:

我在我的MySQL副本(版本5.0.51a-24 + lenny3)上放了一个简单的测试。它表明,在使用正确的查询和测试查询时,您的Rectangle_Index正在使用中。但是,使用正确的查询时,key_len为8,表明并非所有多列索引的所有部分都在使用。也许你的MySQL版本的输出在这方面有所不同。

正如您将从下面的输出中看到的,即使添加了其他索引,在所有情况下仍然会选择Rectangle_Index索引,除了查询中仅引用Y列: / p>

CREATE TABLE `Visual_Node` (
    `Id` bigint(20) NOT NULL AUTO_INCREMENT,
    `X` bigint(20) NOT NULL,
    `Y` bigint(20) NOT NULL,
    `X_plus_Width` bigint(20) DEFAULT NULL,
    `Y_plus_Height` bigint(20) DEFAULT NULL,
    PRIMARY KEY (`Id`),
    KEY `Rectangle_Index` (`X`,`X_plus_Width`,`Y`,`Y_plus_Height`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `Visual_Node` VALUES
      (1,   100000,  1000000,  3000000,  3000000),
      (2,   200000,  2000000,  4000000,  4000000),
      (3,   300000,  3000000,  5000000,  5000000),
      (4,   400000,  4000000,  6000000,  6000000),
      (5,   500000,  5000000,  7000000,  7000000),
      (6,   600000,  6000000,  8000000,  8000000),
      (7,   700000,  7000000,  9000000,  9000000),
      (8,   800000,  8000000, 10000000, 10000000),
      (9,   900000,  9000000, 11000000, 11000000),
      (10, 1000000, 10000000, 12000000, 12000000);

EXPLAIN SELECT * FROM Visual_Node n WHERE n.X < 800000;
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys   | key             | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | n     | range | Rectangle_Index | Rectangle_Index | 8       | NULL |    5 | Using where; Using index |
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+--------------------------+

EXPLAIN SELECT * FROM Visual_Node n WHERE n.Y < 800000;
+----+-------------+-------+-------+---------------+-----------------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys | key             | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+---------------+-----------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | n     | index | NULL          | Rectangle_Index | 34      | NULL |   10 | Using where; Using index |
+----+-------------+-------+-------+---------------+-----------------+---------+------+------+--------------------------+

EXPLAIN SELECT * FROM Visual_Node n
      WHERE 800000 BETWEEN n.X and n.X_plus_Width
      AND 1234567 BETWEEN n.Y and n.Y_plus_Height;
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys   | key             | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | n     | range | Rectangle_Index | Rectangle_Index | 8       | NULL |    5 | Using where; Using index |
+----+-------------+-------+-------+-----------------+-----------------+---------+------+------+--------------------------+

ALTER TABLE `Visual_Node` ADD INDEX `X_Index` (`X`,`X_plus_Width`);
ALTER TABLE `Visual_Node` ADD INDEX `Y_Index` (`Y`,`Y_plus_Height`);

EXPLAIN SELECT * FROM Visual_Node n WHERE n.X < 800000;
+----+-------------+-------+-------+-------------------------+-----------------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys           | key             | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+-------------------------+-----------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | n     | range | Rectangle_Index,X_Index | Rectangle_Index | 8       | NULL |    5 | Using where; Using index |
+----+-------------+-------+-------+-------------------------+-----------------+---------+------+------+--------------------------+

EXPLAIN SELECT * FROM Visual_Node n WHERE n.Y < 800000;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | n     | range | Y_Index       | Y_Index | 8       | NULL |    1 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+

EXPLAIN SELECT * FROM Visual_Node n
      WHERE 800000 BETWEEN n.X and n.X_plus_Width
      AND 1234567 BETWEEN n.Y and n.Y_plus_Height;
+----+-------------+-------+-------+---------------------------------+-----------------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys                   | key             | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+---------------------------------+-----------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | n     | range | Rectangle_Index,X_Index,Y_Index | Rectangle_Index | 8       | NULL |    5 | Using where; Using index |
+----+-------------+-------+-------+---------------------------------+-----------------+---------+------+------+--------------------------+

ALTER TABLE `Visual_Node` ADD INDEX `X` (`X`,`X_plus_Width`);    
ALTER TABLE `Visual_Node` ADD INDEX `X_plus_Width` (`X_plus_Width`);    
ALTER TABLE `Visual_Node` ADD INDEX `Y` (`Y`);
ALTER TABLE `Visual_Node` ADD INDEX `Y_plus_Height` (`Y_plus_Height`);

EXPLAIN SELECT * FROM Visual_Node n WHERE n.X < 800000;
+----+-------------+-------+-------+---------------------------+-----------------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys             | key             | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+---------------------------+-----------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | n     | range | Rectangle_Index,X_Index,X | Rectangle_Index | 8       | NULL |    5 | Using where; Using index |
+----+-------------+-------+-------+---------------------------+-----------------+---------+------+------+--------------------------+

EXPLAIN SELECT * FROM Visual_Node n WHERE n.Y < 800000;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|  1 | SIMPLE      | n     | range | Y_Index,Y     | Y_Index | 8       | NULL |    1 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+

EXPLAIN SELECT * FROM Visual_Node n
    WHERE 800000 BETWEEN n.X and n.X_plus_Width
    AND 1234567 BETWEEN n.Y and n.Y_plus_Height;
+----+-------------+-------+-------+----------------------------------------------------------------+-----------------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys                                                  | key             | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+----------------------------------------------------------------+-----------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | n     | range | Rectangle_Index,X_Index,Y_Index,X,X_plus_Width,Y,Y_plus_Height | Rectangle_Index | 8       | NULL |    5 | Using where; Using index |
+----+-------------+-------+-------+----------------------------------------------------------------+-----------------+---------+------+------+--------------------------+

您可以发布EXPLAIN查询的输出吗?

您使用的是哪个版本的MySQL?

编辑2:

Naktibalda建议的Spatial Extensions,非常酷。我以前没有使用过这些,但如果你能改变你的表结构来使用它们,它们可能会解决你的问题。

好奇,我做了一些研究,这是我的测试脚本的结果:

CREATE TABLE `Spatial_Node` (
  `Id` bigint(20) NOT NULL AUTO_INCREMENT,
  `Rectangle` POLYGON NOT NULL,
  PRIMARY KEY (`Id`),
  SPATIAL KEY `Rectangle` (`Rectangle`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

INSERT INTO `Spatial_Node` (`Rectangle`)
    SELECT Polygon(LineString(
        Point(X,            Y),
        Point(X_plus_Width, Y),
        Point(X_plus_Width, Y_plus_Height),
        Point(X,            Y_plus_Height),
        Point(X,            Y)
))
FROM Visual_Node;

SELECT AsText(`Rectangle`) FROM Spatial_Node
    WHERE MBRContains(Rectangle, Point(100001, 1000001));

+-----------------------------------------------------------------------------------------+
| AsText(`Rectangle`)                                                                     |
+-----------------------------------------------------------------------------------------+
| POLYGON((100000 1000000,3000000 1000000,3000000 3000000,100000 3000000,100000 1000000)) |
+-----------------------------------------------------------------------------------------+

EXPLAIN SELECT AsText(`Rectangle`) FROM Spatial_Node
    WHERE MBRContains(Rectangle, Point(100001, 1000001));

+----+-------------+--------------+-------+---------------+-----------+---------+------+------+-------------+
| id | select_type | table        | type  | possible_keys | key       | key_len | ref  | rows | Extra       |
+----+-------------+--------------+-------+---------------+-----------+---------+------+------+-------------+
|  1 | SIMPLE      | Spatial_Node | range | Rectangle     | Rectangle | 32      | NULL |    1 | Using where |
+----+-------------+--------------+-------+---------------+-----------+---------+------+------+-------------+

我不知道速度会如何比较,但我今天肯定学到了一些新的和令人兴奋的东西。谢谢Naktibalda: - )

答案 2 :(得分:0)

您是否尝试将索引更改为:

CREATE TABLE `Visual_Node` (
  `Id` bigint(20) NOT NULL AUTO_INCREMENT,
  `X` bigint(20) NOT NULL,
  `Y` bigint(20) NOT NULL,
  `X_plus_Width` bigint(20) DEFAULT NULL,
  `Y_plus_Height` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`Id`),
  KEY `X_Index` (`X`),
  KEY `Y_Index` (`Y`),
  KEY `X_Width_Index` (`X_plus_Width`),
  KEY `Y_Height_Index` (`Y_plus_Height`)
) ENGINE=InnoDB AUTO_INCREMENT=4340743 DEFAULT CHARSET=latin1

根据您的AI值判断,您可能希望使用较小的数据集进行测试。