MySQL索引列与连接表

时间:2015-03-24 18:27:15

标签: mysql performance

我正在尝试找出从数据库中提取具有与此类似结构的值的最有效方法:

表格测试:

int id (primary, auto increment)
varchar(50) stuff,
varchar(50) important_stuff;

我需要进行像

这样的查询
select * from test where important_stuff like 'prefix%';

整个表的大小约为1000万行,但important_stuff只有大约500-1000个不同的值。我目前的解决方案是索引important_stuff,但性能不尽如人意。最好是创建一个单独的表格,将不同的important_stuff与某个ID匹配,该表格将存储在' test'表然后再做

(select id from stuff_lookup where important_stuff like 'prefix%') a join select * from test b where b.stuff_id=a.id

或者这个:

select * from test where stuff_id exists in(select id from stuff_lookup where important_stuff like 'prefix%')

优化这类事情的最佳方法是什么?

2 个答案:

答案 0 :(得分:1)

我不是MySQL用户,但我在本地数据库上进行了一些测试。我写了你添加了1000万行,第三列的不同数据加载速度非常快。这些是我的结果。

mysql> describe bigtable;
+-----------------+-------------+------+-----+---------+----------------+
| Field           | Type        | Null | Key | Default | Extra          |
+-----------------+-------------+------+-----+---------+----------------+
| id              | int(11)     | NO   | PRI | NULL    | auto_increment |
| stuff           | varchar(50) | NO   |     | NULL    |                |
| important_stuff | varchar(50) | NO   | MUL | NULL    |                |
+-----------------+-------------+------+-----+---------+----------------+
3 rows in set (0.03 sec)

mysql> select count(*) from bigtable;
+----------+
| count(*) |
+----------+
| 10000089 |
+----------+
1 row in set (2.87 sec)

mysql> select count(distinct important_stuff) from bigtable;
+---------------------------------+
| count(distinct important_stuff) |
+---------------------------------+
|                            1000 |
+---------------------------------+
1 row in set (0.01 sec)

mysql> select distinct important_stuff from bigtable;
....
| is_987          |
| is_988          |
| is_989          |
| is_99           |
| is_990          |
| is_991          |
| is_992          |
| is_993          |
| is_994          |
| is_995          |
| is_996          |
| is_997          |
| is_998          |
| is_999          |
+-----------------+
1000 rows in set (0.15 sec)

重要信息是我刷新了此表的统计信息(在此操作之前,我需要大约10秒才能加载这些数据)。

mysql> optimize table bigtable;

答案 1 :(得分:1)

innodb_buffer_pool_size有多大?有多少RAM可用?前者应该是后者的约70%。你会在一分钟内看到为什么我提出这个设置。

根据您建议的3个SELECT,原始的SELECT将与两个复杂的SELECT一样好。在某些其他案例中,复杂的表述可能会更好。

INDEX(important_stuff)

的“最佳”索引
select * from test where important_stuff like 'prefix%';

现在,让我们研究一下该查询如何与该索引一起使用:

  1. 从“前缀”开始,进入BTree索引。 (努力:几乎是瞬间的)
  2. 向前扫描,例如1000个条目。这将是大约10个InnoDB块(每个16KB)。每个条目都有PRIMARY KEY(id)。 (努力:< = 10次磁盘命中)
  3. 对于每个条目,请查找该行(因此您可以获得“*”)。这是BTree中的1000个PK查找,包含PK和数据。充其量,他们可能都在10个街区。在最坏的情况下,他们可能在1000个独立的区块。 (努力:10-1000块)
  4. 总工作量:~1010块(最差情况)。

    标准旋转磁盘可以处理~100次读/秒。所以。我们正在看10秒钟。

    现在,再次运行查询。你猜怎么着;所有这些块现在都在RAM中(缓存在“buffer_pool”中,希望希望足够所有这些块)。它运行不到1秒钟。

    OPTIMIZE TABLE 是必要的!它是统计信息刷新,而是加速查询的缓存