【问题标题】:My MySQL indexes are efficient?我的 MySQL 索引高效吗?
【发布时间】:2017-07-23 11:39:03
【问题描述】:

我有下表:

mysql> describe as_rilevazioni;
+----------------------------+----------+------+-----+---------+----------------+
| Field                      | Type     | Null | Key | Default | Extra          |
+----------------------------+----------+------+-----+---------+----------------+
| id                         | int(11)  | NO   | PRI | NULL    | auto_increment |
| id_sistema_di_monitoraggio | longtext | NO   | MUL | NULL    |                |
| id_unita                   | longtext | NO   |     | NULL    |                |
| id_sensore                 | longtext | NO   |     | NULL    |                |
| data                       | datetime | NO   |     | NULL    |                |
| timestamp                  | longtext | NO   |     | NULL    |                |
| unita_di_misura            | longtext | NO   |     | NULL    |                |
| misura                     | longtext | NO   |     | NULL    |                |
+----------------------------+----------+------+-----+---------+----------------+
8 rows in set (0.00 sec)

我的桌子上有以下索引:

mysql> show indexes from as_rilevazioni;
+----------------+------------+----------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table          | Non_unique | Key_name | Seq_in_index | Column_name                | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------------+------------+----------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| as_rilevazioni |          0 | PRIMARY  |            1 | id                         | A         |   315865898 |     NULL | NULL   |      | BTREE      |         |               |
| as_rilevazioni |          0 | UNIQUE   |            1 | id_sistema_di_monitoraggio | A         |          17 |        5 | NULL   |      | BTREE      |         |               |
| as_rilevazioni |          0 | UNIQUE   |            2 | id_unita                   | A         |          17 |       10 | NULL   |      | BTREE      |         |               |
| as_rilevazioni |          0 | UNIQUE   |            3 | id_sensore                 | A         |      145225 |       30 | NULL   |      | BTREE      |         |               |
| as_rilevazioni |          0 | UNIQUE   |            4 | data                       | A         |   315865898 |     NULL | NULL   |      | BTREE      |         |               |
+----------------+------------+----------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
5 rows in set (0.02 sec)

恐怕这些索引效率不高,因为基于“数据”列的索引的基数与记录数据的数量一样大! 这些索引加快了我的查询速度,还是占用了大量空间而没有好处?

这是表定义:

CREATE TABLE `as_rilevazioni` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `id_sistema_di_monitoraggio` longtext NOT NULL,
  `id_unita` longtext NOT NULL,
  `id_sensore` longtext NOT NULL,
  `data` datetime NOT NULL,
  `timestamp` longtext NOT NULL,
  `unita_di_misura` longtext NOT NULL,
  `misura` longtext NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `UNIQUE` (`id_sistema_di_monitoraggio`(5),`id_unita`(10),`id_sensore`(30),`data`)
) ENGINE=InnoDB AUTO_INCREMENT=437497044 DEFAULT CHARSET=latin1

我使用的主要查询是:

select * from as_rilevazioni where id_sistema_di_monitoraggio="<value>" and id_unita="<value>" and id_sensore="<value>" and data>="<date_1>" and data<="<date2>"

这是解释的查询:

mysql> explain select * from as_rilevazioni where id_sistema_di_monitoraggio="235" and id_unita="17" and id_sensore="15" and data >= "2015-01-01 00:00:00" order by data;
+----+-------------+----------------+-------+---------------+--------+---------+------+--------+-------------+
| id | select_type | table          | type  | possible_keys | key    | key_len | ref  | rows   | Extra       |
+----+-------------+----------------+-------+---------------+--------+---------+------+--------+-------------+
|  1 | SIMPLE      | as_rilevazioni | range | UNIQUE        | UNIQUE | 59      | NULL | 285522 | Using where |
+----+-------------+----------------+-------+---------------+--------+---------+------+--------+-------------+
1 row in set (0.00 sec)

这是数据和索引的维度:

mysql> SELECT concat(table_schema,'.',table_name) tables,
    ->        concat(round(table_rows/1000000,2),'M') rows,
    ->        concat(round(data_length/(1024*1024*1024),2),'G') data_size,
    ->        concat(round(index_length/(1024*1024*1024),2),'G') index_size,
    ->        concat(round((data_length+index_length)/(1024*1024*1024),2),'G') total_size,
    ->        round(index_length/data_length,2) index_data_ratio
    -> FROM information_schema.TABLES
    -> WHERE table_name="as_rilevazioni"
    -> ORDER BY total_size DESC;
+------------------------------------+---------+-----------+------------+------------+------------------+
| tables                             | rows    | data_size | index_size | total_size | index_data_ratio |
+------------------------------------+---------+-----------+------------+------------+------------------+
| agriculturalsupport.as_rilevazioni | 317.12M | 19.06G    | 10.25G     | 29.31G     |             0.54 |
+------------------------------------+---------+-----------+------------+------------+------------------+
1 row in set (0.02 sec)

有什么建议吗? 谢谢大家!

【问题讨论】:

  • 我不明白你想要什么。您的问题的可能答案 - yesno。看起来一切都正确,所以,我的答案是yes。但是,回答您的问题的唯一方法是explain sql 执行的结果。请执行explain select ... 并检查extra 列内的数据。如果只有using index,那就完美了。如果没有using index,看起来你的索引不起作用。
  • 尝试在id_sistema_di_monitoraggioid_unitaid_sensoredata上添加multiple-column index
  • 已有多列索引。我在原始消息中添加了查询的解释。

标签: mysql indexing innodb


【解决方案1】:
UNIQUE a(5), b(10)

太可怕了。据说只检查a 的前5 个字节以及b 的前10 个字节的唯一性。您可能想检查完整的 ab 的组合是否唯一。

INDEX a(5), b(10)

几乎没有用——它不会超过a,甚至考虑b

INDEX a(5)

有时是无用的。

UNIQUE a, data  -- where `data` is `DATETIME` or `TIMESTAMP`

通常是“错误的”。你确定a不能在一秒钟内出现两次吗?

在查看多列索引时,“基数”通常并不重要。等于表中估计行数的基数意味着它认为该列是唯一的;但它不会指望它。

“高效”是指“不占用'太多'空间”吗? UNIQUE 索引的每一行将占用大约 1+5 + 1+10 + 1+30 + 5 = 53 个字节。将其乘以 317M,您将获得 17GB。增加大约 40% 的开销以获得 23GB。这比 information_schema 中的 10GB 多得多。 (错误涉及许多近似值——可能主要是行数。)

或者,你的意思是“这个索引加快了一些查询”?为了讨论这个问题,我们需要查看查询。 (同时,我已经指出了索引不好的几个原因。)

如果 ID 是数字

如果它们确实是数字,则切换到SMALLINT UNSIGNED(2 个字节)或其他大小。 然后包含这 4 列(和 datalast)的索引很可能会显着加快查询速度。是的,索引会消耗一些磁盘空间,但它可能是值得的。 TEXT,加了“前缀”,根本起不到效率的作用。

索引数字也比字符串便宜。您的 id_unita(10) 在索引的每一行中最多占用 11 个字节; MEDIUMINT UNSIGNED 占用固定的 3 个字节。也就是说,索引会更小并且更有用。

【讨论】:

  • “高效”的意思是“这个索引加快了我的查询速度?或者它占用了大量空间而没有好处?” :) 查询是:select * from as_rilevazioni where id_sistema_di_monitoraggio="235" and id_unita="17" and id_sensore="15" and data &gt;= "2015-01-01 00:00:00" order by data;
  • 看我的补充。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-23
相关资源
最近更新 更多