use*_*770 5 mysql innodb index mysql-5.6
现在有两种方法可以在 MySQL 中构建表的索引:
在第一个过程中,我们将拥有连续的数据(所有字段)页面,然后是索引页面。所以当我们使用索引查询时,MySQL 必须首先加载索引页并找出匹配的键,并且必须在数据页上查找那些主键。为此,它必须再次加载数据页以获取数据。当我们有更大的索引扫描时这很有用,因为我们所有的索引都是连续加载的。
在索引创建的第二种方式中,过滤后的索引页很可能包含与它们同时创建的靠近它的数据页。所以我想小范围扫描的查找速度会更快。
我的理解正确吗?
更新:
我应该在第一种导入数据的方式中提到“PRIMARY KEY 已启用”(自动递增 id 列)。因此,不会生成内部 rowid,并且由于我们不打算添加 PRIMARY KEY,因此会保存大量 IO。
正如您所指出的,当我们使用第二种方法导入数据时会出现碎片。
考虑到我的要求是更大范围的扫描(扫描~100M 行),我想我会采用第一种导入数据的方式。
6 月 8 日 11:30 更新
CREATE TABLE `table_dummy` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`column1` bigint(20) DEFAULT NULL,
`column2` bigint(20) DEFAULT NULL,
`column3` bigint(20) DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`column4` tinyint(1) DEFAULT NULL,
`column5` tinyint(4) DEFAULT NULL,
`column6` bigint(20) DEFAULT NULL,
`column6_created_at` datetime DEFAULT NULL,
`column7` int(11) DEFAULT NULL,
`column8` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `twtaccount_id_2` (`column1`,`column2`),
KEY `twtaccount_id` (`column1`,`created_at`,`column5`),
KEY `twt_user_id` (`column3`,`created_at`,`column5`),
KEY `original_status_id` (`column6`,`column3`,`followers_count`)
)
Run Code Online (Sandbox Code Playgroud)
引擎是 INNODB
这个表有大约 800M 的记录,我进行了转储并以两种方式导入它。
方法 1:仅使用主键创建表并导入整个数据。然后我给出了一个alter语句来添加剩余的索引。
方法 2:使用索引创建表并完成转储。这花费了更多的时间。
PS 与通过“方法 2”转储的表的大小相比,通过“方法 1”生成的表的大小要小约 30GB。方法 1 比“方法 2”花费的时间少得多,几乎是速度的两倍。
我主要关心的是当我选择扫描范围广泛的索引(“仅索引扫描”)时表的性能。
第一种方式,你是正确的。这就是为什么我说软的。
InnoDB 有一个聚集索引,内部称为 gen_clust_index。基本上,它是rowid在幕后为 InnoDB 表创建的索引(或者如果您像我一样来自新泽西州泽西城,则在幕后创建)。这些 rowid 附加到所有二级索引。
PRIMARY KEY如果组成KEYPRIMARY KEY的列的宽度PRIMARY比rowid.
对于 InnoDB,第二种创建索引的方法更有意义,因为您没有PRIMARY KEY在幕后交换 的定义。这是您已经提到的好处 ( ) 的补充data page near to it as they were created at the same time。第一种索引方法在这方面没有任何收获,充其量只是收支平衡。
虽然第二种方法更适合需求(look up will be faster for a small range scans),但我对您有一个非常强烈的警告:如果您PRIMARY KEY用已经排序的列数据填充,您很可能最终会遇到一些索引碎片(请参阅我对帖子Oct 26, 2012How badly does innodb 片段面对有些无序插入?)如果您知道自己正在进行小范围扫描,那么这是一个不错的权衡。
在这种情况下,同样的警告也适用。你将得到一个支离破碎的PRIMARY KEY. 证明在我对帖子May 01, 2014Why would the size of MySQL MyISAM table Index (aka MYI file) not match after mysqldump import? 的回答中得到了表达。
要手动证明,请执行以下操作
步骤01:从数据库服务器mysqldump数据
步骤02:将其加载到测试服务器中
运行查询
SELECT IFNULL(ENGINE,'Total') "Storage Engine",
LPAD(CONCAT(FORMAT(DAT/POWER(1024,pw1),2),' ',
SUBSTR(units,pw1*2+1,2)),17,' ') "Data Size",
LPAD(CONCAT(FORMAT(NDX/POWER(1024,pw2),2),' ',
SUBSTR(units,pw2*2+1,2)),17,' ') "Index Size",
LPAD(CONCAT(FORMAT(TBL/POWER(1024,pw3),2),' ',
SUBSTR(units,pw3*2+1,2)),17,' ') "Total Size" FROM
(SELECT ENGINE,DAT,NDX,TBL,IF(px>4,4,px) pw1,
IF(py>4,4,py) pw2,IF(pz>4,4,pz) pw3 FROM
(SELECT *,FLOOR(LOG(IF(DAT=0,1,DAT))/LOG(1024)) px,
FLOOR(LOG(IF(NDX=0,1,NDX))/LOG(1024)) py,
FLOOR(LOG(IF(TBL=0,1,TBL))/LOG(1024)) pz
FROM (SELECT ENGINE,SUM(data_length) DAT,SUM(index_length) NDX,
SUM(data_length+index_length) TBL FROM (SELECT engine,data_length,index_length
FROM information_schema.tables WHERE table_schema NOT IN
('information_schema','performance_schema','mysql') AND ENGINE IS NOT NULL) AAA
GROUP BY ENGINE WITH ROLLUP) AAA ) AA) A,(SELECT ' BKBMBGBTB' units) B;
Run Code Online (Sandbox Code Playgroud)
步骤04:来自测试服务器的mysqldump
步骤05:再次将测试服务器的转储重新加载回测试服务器
步骤 06:运行步骤 03 中的查询
有时,大组数据在重新加载mysql数据时会产生不同的大小
底线:对于 InnoDB,这两种方法都没有比另一种方法有显着优势。
| 归档时间: |
|
| 查看次数: |
594 次 |
| 最近记录: |