MySQL性能较慢*使用*索引?
我正在编写一个应用程序,它使用MySQL将文件散列数据保存到一个简单的数据库中,其中只有一个表。我创建了如下内容:MySQL性能较慢*使用*索引?,mysql,database,performance,indexing,Mysql,Database,Performance,Indexing,我正在编写一个应用程序,它使用MySQL将文件散列数据保存到一个简单的数据库中,其中只有一个表。我创建了如下内容: CREATE DATABASE IF NOT EXISTS hash_db; CREATE TABLE IF NOT EXISTS hash_db.main_tbl ( sha256 CHAR(64) PRIMARY KEY , sha1 CHAR(40)
CREATE DATABASE IF NOT EXISTS hash_db;
CREATE TABLE IF NOT EXISTS hash_db.main_tbl
(
sha256 CHAR(64) PRIMARY KEY ,
sha1 CHAR(40) UNIQUE KEY ,
md5 CHAR(32) UNIQUE KEY ,
created DATETIME ,
modified DATETIME ,
size BIGINT ,
ext VARCHAR(260) ,
path TEXT(32768) ,
new_record BOOL
)
ENGINE = MyISAM
CREATE UNIQUE INDEX sha256_idx ON hash_db.main_tbl (sha256)
CREATE UNIQUE INDEX sha1_idx ON hash_db.main_tbl (sha1)
CREATE UNIQUE INDEX md5_idx ON hash_db.main_tbl (md5)
EXPLAIN EXTENDED SELECT * FROM main_hash_db.main_tbl WHERE md5 = '...'
+----+-------------+----------+-------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+-------+---------------+------+---------+-------+------+----------+-------+
| 1 | SIMPLE | main_tbl | const | md5 | md5 | 97 | const | 1 | 100.00 | NULL |
+----+-------------+----------+-------+---------------+------+---------+-------+------+----------+-------+
EXPLAIN EXTENDED SELECT * FROM main_hash_db.main_tbl WHERE md5 = '...' UNION ALL SELECT * FROM main_hash_db.main_tbl WHERE sha1 = '...'
+----+--------------+------------+-------+-----------------------+------+---------+-------+------+----------+-----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+------------+-------+-----------------------+------+---------+-------+------+----------+-----------------+
| 1 | PRIMARY | main_tbl | const | md5 | md5 | 97 | const | 1 | 100.00 | NULL |
| 2 | UNION | main_tbl | const | sha1,sha1_idx,md5_idx | sha1 | 121 | const | 1 | 100.00 | NULL |
| NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+------------+-------+-----------------------+------+---------+-------+------+----------+-----------------+
EXPLAIN EXTENDED SELECT * FROM main_hash_db.main_tbl WHERE md5 = '...' UNION ALL SELECT * FROM main_hash_db.main_tbl WHERE sha1 = '...' UNION ALL SELECT * FROM main_hash_db.main_tbl WHERE sha256 = '...'
+----+--------------+--------------+-------+-----------------------+---------+---------+-------+------+----------+-----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+--------------+-------+-----------------------+---------+---------+-------+------+----------+-----------------+
| 1 | PRIMARY | main_tbl | const | md5 | md5 | 97 | const | 1 | 100.00 | NULL |
| 2 | UNION | main_tbl | const | sha1,sha1_idx,md5_idx | sha1 | 121 | const | 1 | 100.00 | NULL |
| 3 | UNION | main_tbl | const | PRIMARY,sha256_idx | PRIMARY | 192 | const | 1 | 100.00 | NULL |
| NULL | UNION RESULT | <union1,2,3> | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+--------------+-------+-----------------------+---------+---------+-------+------+----------+-----------------+
然后我只做表单的简单选择和插入:
SELECT * FROM hash_db.main_tbl WHERE
sha256 = '...' OR
sha1 = '...' OR
md5 = '...'
INSERT INTO hash_db.main_tbl
(sha256, sha1, md5, created, modified, size, ext, path, new_record) VALUES
(
'...' ,
'...' ,
'...' ,
FROM_UNIXTIME(...) ,
FROM_UNIXTIME(...) ,
... ,
'...' ,
'...' ,
TRUE
)
数据几乎是随机的,唯一性概率非常高(不是说它应该重要,还是应该重要?)。
第一个问题,InnoDB比MyISAM慢很多(~7倍)这样的使用是正常的吗?我读到它应该是另一种方式(尝试使用512M innodb_缓冲区_池_大小,没有区别)
第二。。。我已经测试了有索引和没有索引(MyISAM),而有索引的版本实际上更慢。这些是我的应用程序测量的实际性能数据(使用C中的性能计数器):
我得到的数据是可重复的。我已经用放大的键缓冲区大小(32M,默认为8M)进行了测试
我做错了什么或错过了什么
================================================================================
根据Gordon Linoff的建议编辑:
我试过使用UNION ALL,但实际上性能下降了,精确到每秒70次选择。
EXPLAIN的输出如下所示:
CREATE DATABASE IF NOT EXISTS hash_db;
CREATE TABLE IF NOT EXISTS hash_db.main_tbl
(
sha256 CHAR(64) PRIMARY KEY ,
sha1 CHAR(40) UNIQUE KEY ,
md5 CHAR(32) UNIQUE KEY ,
created DATETIME ,
modified DATETIME ,
size BIGINT ,
ext VARCHAR(260) ,
path TEXT(32768) ,
new_record BOOL
)
ENGINE = MyISAM
CREATE UNIQUE INDEX sha256_idx ON hash_db.main_tbl (sha256)
CREATE UNIQUE INDEX sha1_idx ON hash_db.main_tbl (sha1)
CREATE UNIQUE INDEX md5_idx ON hash_db.main_tbl (md5)
EXPLAIN EXTENDED SELECT * FROM main_hash_db.main_tbl WHERE md5 = '...'
+----+-------------+----------+-------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+----------+-------+---------------+------+---------+-------+------+----------+-------+
| 1 | SIMPLE | main_tbl | const | md5 | md5 | 97 | const | 1 | 100.00 | NULL |
+----+-------------+----------+-------+---------------+------+---------+-------+------+----------+-------+
EXPLAIN EXTENDED SELECT * FROM main_hash_db.main_tbl WHERE md5 = '...' UNION ALL SELECT * FROM main_hash_db.main_tbl WHERE sha1 = '...'
+----+--------------+------------+-------+-----------------------+------+---------+-------+------+----------+-----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+------------+-------+-----------------------+------+---------+-------+------+----------+-----------------+
| 1 | PRIMARY | main_tbl | const | md5 | md5 | 97 | const | 1 | 100.00 | NULL |
| 2 | UNION | main_tbl | const | sha1,sha1_idx,md5_idx | sha1 | 121 | const | 1 | 100.00 | NULL |
| NULL | UNION RESULT | <union1,2> | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+------------+-------+-----------------------+------+---------+-------+------+----------+-----------------+
EXPLAIN EXTENDED SELECT * FROM main_hash_db.main_tbl WHERE md5 = '...' UNION ALL SELECT * FROM main_hash_db.main_tbl WHERE sha1 = '...' UNION ALL SELECT * FROM main_hash_db.main_tbl WHERE sha256 = '...'
+----+--------------+--------------+-------+-----------------------+---------+---------+-------+------+----------+-----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+--------------+-------+-----------------------+---------+---------+-------+------+----------+-----------------+
| 1 | PRIMARY | main_tbl | const | md5 | md5 | 97 | const | 1 | 100.00 | NULL |
| 2 | UNION | main_tbl | const | sha1,sha1_idx,md5_idx | sha1 | 121 | const | 1 | 100.00 | NULL |
| 3 | UNION | main_tbl | const | PRIMARY,sha256_idx | PRIMARY | 192 | const | 1 | 100.00 | NULL |
| NULL | UNION RESULT | <union1,2,3> | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+--------------+-------+-----------------------+---------+---------+-------+------+----------+-----------------+
================================================================================
进一步讨论后进行第三次编辑(见下文)。以下是原始查询的EXPLAIN
输出(未定义其他索引,数据库如上所述创建):
以我的应用程序衡量的性能:
Selects per second: 500.6
Inserts per second: 1394.8
这是3次选择的结果(单独发布,而不是联合发布):
首先,没有索引的
insert
会更快。这里没有什么神秘之处。不必维护索引。事实上,在进行大型插入时,一个好的策略通常是先删除索引,再进行插入,然后重建索引
选择
更麻烦。毕竟,这是您希望使用索引的地方。您的查询是:
SELECT *
FROM hash_db.main_tbl
WHERE sha256 = '...' OR
sha1 = '...' OR
md5 = '...';
这恰好是索引使用的最坏情况。您需要查看explain
以了解索引是如何使用的
我的建议是这样编写查询:
SELECT *
FROM hash_db.main_tbl
WHERE sha256 = '...'
UNION ALL
SELECT *
FROM hash_db.main_tbl
sha1 = '...'
UNION ALL
SELECT *
FROM hash_db.main_tbl
WHERE md5 = '...';
(如果确实要消除重复项,请使用union
。)
这应该利用每个子查询的每个索引,并为您提供所需的性能。首先,您希望在没有索引的情况下插入
会更快。这里没有什么神秘之处。不必维护索引。事实上,在进行大型插入时,一个好的策略通常是先删除索引,再进行插入,然后重建索引
选择
更麻烦。毕竟,这是您希望使用索引的地方。您的查询是:
SELECT *
FROM hash_db.main_tbl
WHERE sha256 = '...' OR
sha1 = '...' OR
md5 = '...';
这恰好是索引使用的最坏情况。您需要查看explain
以了解索引是如何使用的
我的建议是这样编写查询:
SELECT *
FROM hash_db.main_tbl
WHERE sha256 = '...'
UNION ALL
SELECT *
FROM hash_db.main_tbl
sha1 = '...'
UNION ALL
SELECT *
FROM hash_db.main_tbl
WHERE md5 = '...';
(如果确实要消除重复项,请使用union
。)
这应该利用每个子查询的每个索引,并为您提供所需的性能。首先,您希望在没有索引的情况下插入会更快。这里没有什么神秘之处。不必维护索引。事实上,在进行大型插入时,一个好的策略通常是先删除索引,再进行插入,然后重建索引
选择
更麻烦。毕竟,这是您希望使用索引的地方。您的查询是:
SELECT *
FROM hash_db.main_tbl
WHERE sha256 = '...' OR
sha1 = '...' OR
md5 = '...';
这恰好是索引使用的最坏情况。您需要查看explain
以了解索引是如何使用的
我的建议是这样编写查询:
SELECT *
FROM hash_db.main_tbl
WHERE sha256 = '...'
UNION ALL
SELECT *
FROM hash_db.main_tbl
sha1 = '...'
UNION ALL
SELECT *
FROM hash_db.main_tbl
WHERE md5 = '...';
(如果确实要消除重复项,请使用union
。)
这应该利用每个子查询的每个索引,并为您提供所需的性能。首先,您希望在没有索引的情况下插入会更快。这里没有什么神秘之处。不必维护索引。事实上,在进行大型插入时,一个好的策略通常是先删除索引,再进行插入,然后重建索引
选择
更麻烦。毕竟,这是您希望使用索引的地方。您的查询是:
SELECT *
FROM hash_db.main_tbl
WHERE sha256 = '...' OR
sha1 = '...' OR
md5 = '...';
这恰好是索引使用的最坏情况。您需要查看explain
以了解索引是如何使用的
我的建议是这样编写查询:
SELECT *
FROM hash_db.main_tbl
WHERE sha256 = '...'
UNION ALL
SELECT *
FROM hash_db.main_tbl
sha1 = '...'
UNION ALL
SELECT *
FROM hash_db.main_tbl
WHERE md5 = '...';
(如果确实要消除重复项,请使用union
。)
这将利用每个子查询的每个索引,并提供您想要的性能。您将降低性能并减慢数据库的流动,因为您将创建大量索引
每次插入一个元组时,这意味着您将直接增加系统SGBD中的索引数
当你做选择的时候,它就像一项研究。。大量的指标对系统提出了挑战;和priority一样,您将拥有大量的优先级—在数据库中有1000个元组,有3000个索引
每个软件都有自己的索引管理方法;你必须知道如何掌握索引,然后才能将系统推向最大的潜能
例如,您可以使用带有索引的trrigrs来实现良好的平衡因为您将创建大量索引,因此会降低性能并减慢数据库的运行速度
每次插入一个元组时,这意味着您将直接增加系统SGBD中的索引数
当你做选择的时候,它就像一项研究。。大量的指标对系统提出了挑战;和priority一样,您将拥有大量的优先级,在数据库中有1000个元组