MySQL 索引大于存储的数据
Posted
技术标签:
【中文标题】MySQL 索引大于存储的数据【英文标题】:MySQL Index is bigger than the data stored 【发布时间】:2011-08-08 11:20:37 【问题描述】:我有一个包含以下统计信息的数据库
Tables Data Index Total
11 579,6 MB 0,9 GB 1,5 GB
因此,您可以看到索引接近 2 倍大。有一张表有大约 700 万行,至少占了其中的 99%。
我也有两个非常相似的索引
a) UNIQUE KEY `idx_customer_invoice` (`customer_id`,`invoice_no`),
b) KEY `idx_customer_invoice_order` (`customer_id`,`invoice_no`,`order_no`)
更新:这是最大表的表定义(至少在结构上)
CREATE TABLE `invoices` (
`id` int(10) unsigned NOT NULL auto_increment,
`customer_id` int(10) unsigned NOT NULL,
`order_no` varchar(10) default NULL,
`invoice_no` varchar(20) default NULL,
`customer_no` varchar(20) default NULL,
`name` varchar(45) NOT NULL default '',
`archived` tinyint(4) default NULL,
`invoiced` tinyint(4) default NULL,
`time` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
`group` int(11) default NULL,
`customer_group` int(11) default NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_customer_invoice` (`customer_id`,`invoice_no`),
KEY `idx_time` (`time`),
KEY `idx_order` (`order_no`),
KEY `idx_customer_invoice_order` (`customer_id`,`invoice_no`,`order_no`)
) ENGINE=InnoDB AUTO_INCREMENT=9146048 DEFAULT CHARSET=latin1 |
更新 2:
mysql> show indexes from invoices;
+----------+------------+----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+----------+------------+----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| invoices | 0 | PRIMARY | 1 | id | A | 7578066 | NULL | NULL | | BTREE | |
| invoices | 0 | idx_customer_invoice | 1 | customer_id | A | 17 | NULL | NULL | | BTREE | |
| invoices | 0 | idx_customer_invoice | 2 | invoice_no | A | 7578066 | NULL | NULL | YES | BTREE | |
| invoices | 1 | idx_time | 1 | time | A | 541290 | NULL | NULL | | BTREE | |
| invoices | 1 | idx_order | 1 | order_no | A | 6091 | NULL | NULL | YES | BTREE | |
| invoices | 1 | idx_customer_invoice_order | 1 | customer_id | A | 17 | NULL | NULL | | BTREE | |
| invoices | 1 | idx_customer_invoice_order | 2 | invoice_no | A | 7578066 | NULL | NULL | YES | BTREE | |
| invoices | 1 | idx_customer_invoice_order | 3 | order_no | A | 7578066 | NULL | NULL | YES | BTREE | |
+----------+------------+----------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
我的问题是:
-
有没有办法在 MySQL 中找到未使用的索引?
是否存在影响索引大小的常见错误?
可以安全地删除 indexA 吗?
如何衡量每个索引的大小?我得到的只是所有索引的总和。
【问题讨论】:
如果您可以为任何大表运行一些show create table
s 并发布输出,将会很有帮助。
【参考方案1】:
我可能错了,但是第一个索引 (idx_customer_invoice
) 是唯一的,第二个 (idx_customer_invoice_order
) 不是,所以当你删除它时你可能会失去唯一性约束。没有?
【讨论】:
【参考方案2】:-
indexA 可以删除,因为有一个
indexB 包括 indexA
您的索引长度有什么影响
您的列类型和列长
使用:
从 information_schema.tables 中选择 index_length 其中 table_name='your_table_name' 和 table_schema='your_db_name';
获取您的表 index_length
【讨论】:
3.这给了我一个数字,1003831296,是什么意思? @Peter Lindqvist 索引长度为 1003831296B ;您还可以使用显示表状态,例如“your_table_name” 嗯,我想看看各个索引的大小。【参考方案3】:您可以删除索引 A,因为正如您所指出的,它是另一个索引的子集。并且可以在不中断正常处理的情况下执行此操作。
索引文件的大小本身并不令人担忧,净收益是积极的很容易成为事实。换句话说,索引的有用性和价值不应该因为它导致一个大文件而被打折扣。
索引设计是一门复杂而微妙的艺术,涉及对查询优化器解释和广泛测试的深入理解。但是一个常见的错误是在索引中包含的字段太少以使其更小。另一种是测试数据不足或代表性不足的指标。
【讨论】:
我可以同意“微妙的艺术”。【参考方案4】:使用
show indexes from table;
定义您在特定表中拥有哪些索引。基数会说明您的索引有多有用。
您可以安全地删除索引(它不会破坏表),但请注意:某些查询可能执行得较慢。首先你应该分析你的查询来决定你是否需要某个索引。
不过,我认为您无法找出特定索引的数据长度。
但是,我想你可能认为如果索引长度大于数据长度两倍是不正常的......好吧,你错了。您的所有索引都可能有用;)如果您有一个提供大量信息的表,并且您必须在大量列上进行搜索,那么该表的索引很容易成为该表的 2 倍大表格数据。
【讨论】:
您能具体说明基数与有用性的对应关系吗?索引的存在是有原因的,针对此表的查询性能对应用程序至关重要。 但是,我很高兴听到它至少没有异常......:P 官方文档中说:“基数越高,MySQL在做join时使用索引的机会就越大”。实际上,这意味着该列将在连接中使用的次数多于基数较低的其他列。基数评估基于统计数据。具体如何?嗯...我不知道 :) 如果基数很高,这个索引也会消耗更多的容量,因为“基数是对索引中唯一值数量的估计”。 @Peter Lindqvist,绝对不是。事实上,如果我们在我工作的站点(每天 600k+ 的用户)的主表上没有很多索引,我们的 MySQL 服务器将总是关闭。此表中的索引长度/数据长度为 2(索引为 2 倍)。存储引擎是 InnoDB。就像你的情况一样。 而且...是的。我同意同事的观点:indexA 可能会被删除。【参考方案5】:有没有办法在 MySQL 中找到未使用的索引?
数据库引擎优化器会在尝试优化您的查询时选择合适的索引。根据您上次收集索引统计信息的时间,选择的索引会有所不同。由于新的数据重新分区,未使用的索引可能会突然被使用。
可以安全地删除 indexA 吗?
如果 indexA 和 indexB 是 B-Tree 索引,我会说是的。这是因为以相同顺序以相同列开头的索引将具有相同的结构。
【讨论】:
另外两个问题我不确定我能否正确回答。以上是关于MySQL 索引大于存储的数据的主要内容,如果未能解决你的问题,请参考以下文章
mysql 数据库,表每天会插入30W条数据,该表数据千万级,查询效率很慢,建立索引是不是利大于弊?