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)

我正在编写一个应用程序,它使用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) 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个元组