简体   繁体   中英

MyISAM read is much slower than innodb

I am trying to compare the myisam and innodb write/read performance, but I am suprised that the myisam's read is much more slower than innodb while its write is much more faster, this is totally opposite compared to what I have learned.

The mysql version is 5.7.18-0ubuntu0.16.04.1.

here are my two tables:

mysql> show create table inno_1;
+--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table  | Create Table                                                                                                                                                                                                                                                                                                      |
+--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| inno_1 | CREATE TABLE `inno_1` (
  `id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
  `name` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
+--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+



mysql> show create table isam_1;
+--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table  | Create Table                                                                                                                                                                                                                                                                                                      |
+--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| isam_1 | CREATE TABLE `isam_1` (
  `id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
  `name` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
+--------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

I tried to write twice 50000 rows to the two tables

[2017-08-07 15:57:12]  [0.86ms]  INSERT INTO `inno_1` (`id`,`name`,`created_at`,`updated_at`) VALUES ('11e77b46-0576-5c30-8e53-1c1b0d1700f9','xxx','2017-08-07 15:57:12','2017-08-07 15:57:12')  
[1 rows affected or returned ] 
insert time : 1m23.905679587s



[2017-08-07 15:55:49]  [0.11ms]  INSERT INTO `isam_1` (`id`,`name`,`created_at`,`updated_at`) VALUES ('11e77b45-d416-79b0-8804-1c1b0d1700f9','xxx','2017-08-07 15:55:49','2017-08-07 15:55:49')  
[1 rows affected or returned ] 
insert time : 5.500709602s

while for the read:

[2017-08-07 15:57:17]  [20.95ms]  SELECT * FROM `inno_1`   ORDER BY id asc LIMIT 1000 OFFSET 100000  
[0 rows affected or returned ] 
select time : 2.076151355s


[2017-08-07 15:56:24]  [353.06ms]  SELECT * FROM `isam_1`   ORDER BY id asc LIMIT 1000 OFFSET 100000  
[0 rows affected or returned ] 
select time : 32.030940358s

I don't understand why it is so different from the official advice, if I changed the id to int, the myisam's read gets improved a lot.

mysql> show create table inno;
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                                                                                     |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| inno  | CREATE TABLE `inno` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=50001 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> show create table isam;
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                                                                                     |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| isam  | CREATE TABLE `isam` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=50001 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

myisam

[2017-08-07 16:08:37]  [0.09ms]  INSERT INTO `isam` (`name`,`created_at`,`updated_at`) VALUES ('xxx','2017-08-07 16:08:37','2017-08-07 16:08:37')  
[1 rows affected or returned ] 
insert time : 4.745437221s


[2017-08-07 16:08:41]  [12.55ms]  SELECT * FROM `isam`   ORDER BY id asc LIMIT 1000 OFFSET 50000  
[0 rows affected or returned ] 
select time : 1.105638295s

innodb:

[2017-08-07 16:09:26]  [0.87ms]  INSERT INTO `inno` (`name`,`created_at`,`updated_at`) VALUES ('xxx','2017-08-07 16:09:26','2017-08-07 16:09:26')  
[1 rows affected or returned ] 
insert time : 1m28.577975501s


[2017-08-07 16:09:30]  [9.58ms]  SELECT * FROM `inno`   ORDER BY id asc LIMIT 1000 OFFSET 50000  
[0 rows affected or returned ] 
select time : 739.580336ms

could anyone explain?

UPDATE:

I use 10 threads for writing first, then 1 thread for reading.

Black swans do exist; you just have not seen any yet.

Writes

  • Transactions: MyISAM has no such concept. InnoDB, by default, "autocommits" each of your INSERTs immediately. This essentially requires an extra disk hit; that is what slows down InnoDB. If, on the other hand, you did all the inserts in a single transaction (which is logical for your fabricated test), it would run much faster, maybe as fast as InnoDB.

  • innodb_flush_log_at_trx_commit can partially control the above overhead -- at the potential risk to safety.

  • Batching: A single INSERT statement with 100 rows will run about 10 times as fast as 100 single-row INSERTs .

  • Both engines have some optimization of inserting at the "end" of the table. Keep in mind that this is just one write pattern, so drawing a conclusion here is risky.

  • Your Write timings differ by a factor of about 10:1. This is consistent with a spinning HDD when you need to read versus having the block cached. Using SSD (Flash) would shrink that ratio significantly.

Reads

  • MyISAM indexes, including the PRIMARY KEY , are in separate BTrees. They 'point' to the data via a byte offset (or record number). This level of indirection causes your particular read to run slower. Other benchmarks may run faster.

  • InnoDB "clusters" the PK with the data, hence the extra lookup is avoided.

Id

  • If id is monotonically increasing, data will be written to the 'end'. (End of data file (.MYD) and end of PK BTree (in .MYI) for MyISAM; End of data+PK BTree for InnoDB.)

  • If id jumps around, as you are apparently doing with a UUID, then other things are happening. MyISAM's data is appended to, but the BTree for the PK is randomly updated. InnoDB only needs to randomly update the data+PK BTree.

  • UUID is terrible with cache is blown. Once the BTree for the UUID (PK and/or data) is bigger than can be cached, performance goes downhill. Eventually, the cache is useless and every INSERT is a read-modify-write disk hit to update the PK. This impacts both engines, but in slightly different ways. Since your benchmark involves only a few megabytes, you probably did not hit this.

Caches

  • MyISAM uses the key_buffer for caching 1KB index blocks. It lets the OS cache data blocks.

  • InnoDB uses the buffer_pool for caching 16KB blocks for both data and index blocks.

  • Since the OS probably uses 4KB for the allocation unit on disk, one engine is hitting a fraction of a disk block; the other is grabbing multiple disk blocks at once. This difference translates into slightly slower are faster benchmarks, depending on the randomness of the block accesses, etc.

  • Improper setting of key_buffer_size and innodb_buffer_pool_size can have a devastating effect on performance. What did you set them to, and how much RAM do you have?

OFFSET

  • LIMIT 1000 OFFSET 100000 is very unrealistic. It says to step over 100000 rows, one at a time; then fetch 1000. Almost no "real" code uses OFFSET .

  • Furthermore, that OFFSET is guaranteed to read to the end of the table, then not have any rows to actually read. Again, unrealistic.

Benchmarks are a way to generate Fake News.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM