Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么MySQL InnoDB插入速度如此之慢?_Mysql_Performance_Innodb - Fatal编程技术网

为什么MySQL InnoDB插入速度如此之慢?

为什么MySQL InnoDB插入速度如此之慢?,mysql,performance,innodb,Mysql,Performance,Innodb,我使用大随机数作为键(来自另一个系统)。在相当小(比如几百万行)的表上进行插入和更新所花费的时间比我认为合理的要长得多 我提炼了一个非常简单的测试来说明。在测试表中,我试图使其尽可能简单;我真正的代码没有这么简单的布局,它有关系和附加索引等等。但是,更简单的设置会显示出相同的性能 结果如下: creating the MyISAM table took 0.000 seconds creating 1024000 rows of test data took 1.243 seconds inse

我使用大随机数作为键(来自另一个系统)。在相当小(比如几百万行)的表上进行插入和更新所花费的时间比我认为合理的要长得多

我提炼了一个非常简单的测试来说明。在测试表中,我试图使其尽可能简单;我真正的代码没有这么简单的布局,它有关系和附加索引等等。但是,更简单的设置会显示出相同的性能

结果如下:

creating the MyISAM table took 0.000 seconds
creating 1024000 rows of test data took 1.243 seconds
inserting the test data took 6.335 seconds
selecting 1023742 rows of test data took 1.435 seconds
fetching 1023742 batches of test data took 0.037 seconds
dropping the table took 0.089 seconds
creating the InnoDB table took 0.276 seconds
creating 1024000 rows of test data took 1.165 seconds
inserting the test data took 3433.268 seconds
selecting 1023748 rows of test data took 4.220 seconds
fetching 1023748 batches of test data took 0.037 seconds
dropping the table took 0.288 seconds
将1M行插入MyISAM需要6秒;进入InnoDB需要3433秒

我做错了什么?什么是配置错误?(MySQL是一个具有默认值的普通Ubuntu安装)

以下是测试代码:

import sys, time, random
import MySQLdb as db

# usage: python script db_username db_password database_name

db = db.connect(host="127.0.0.1",port=3306,user=sys.argv[1],passwd=sys.argv[2],db=sys.argv[3]).cursor()

def test(engine):

    start = time.time() # fine for this purpose
    db.execute("""
CREATE TEMPORARY TABLE Testing123 (
k INTEGER PRIMARY KEY NOT NULL,
v VARCHAR(255) NOT NULL
) ENGINE=%s;"""%engine)
    duration = time.time()-start
    print "creating the %s table took %0.3f seconds"%(engine,duration)

    start = time.time()
    # 1 million rows in 100 chunks of 10K
    data = [[(str(random.getrandbits(48)) if a&1 else int(random.getrandbits(31))) for a in xrange(10*1024*2)] for b in xrange(100)]
    duration = time.time()-start
    print "creating %d rows of test data took %0.3f seconds"%(sum(len(rows)/2 for rows in data),duration)

    sql = "REPLACE INTO Testing123 (k,v) VALUES %s;"%("(%s,%s),"*(10*1024))[:-1]
    start = time.time()
    for rows in data:
        db.execute(sql,rows)
    duration = time.time()-start
    print "inserting the test data took %0.3f seconds"%duration

    # execute the query
    start = time.time()
    query = db.execute("SELECT k,v FROM Testing123;")
    duration = time.time()-start
    print "selecting %d rows of test data took %0.3f seconds"%(query,duration)

    # get the rows in chunks of 10K
    rows = 0
    start = time.time()
    while query:
        batch = min(query,10*1024)
        query -= batch
        rows += len(db.fetchmany(batch))
    duration = time.time()-start
    print "fetching %d batches of test data took %0.3f seconds"%(rows,duration)

    # drop the table
    start = time.time()
    db.execute("DROP TABLE Testing123;")
    duration = time.time()-start
    print "dropping the table took %0.3f seconds"%duration


test("MyISAM")
test("InnoDB")

InnoDB具有事务支持,您没有使用显式事务,因此InnoDB必须在每条语句()之后进行提交

在循环之前执行此命令:

START TRANSACTION
这个在你循环之后

COMMIT

InnoDB不能很好地处理“随机”主键。尝试按顺序键或自动递增,我相信您会看到更好的性能。您的“真实”键字段仍然可以被索引,但是对于批量插入,您最好在插入完成后删除并重新创建该索引。我很想看看你的基准测试

一些相关问题


InnoDB的默认值实际上非常糟糕。InnoDB非常依赖RAM,如果您调整设置,您可能会发现更好的结果。以下是我使用的指南

我需要同时在MyISAM和InnoDB中测试大量插入的应用程序。只有一个设置解决了我遇到的速度问题。请尝试设置以下内容:

innodb_flush_log_at_trx_commit = 2
通过阅读有关设置的信息,确保您了解风险


另请参见和

我在我的系统上得到了非常不同的结果,但这不是使用默认值。您可能在innodb日志文件大小方面遇到了瓶颈,默认情况下为5M。在innodb日志文件大小=100M时,我得到如下结果(所有数字以秒为单位):


增加innodb日志文件的
size
将使速度提高几秒钟。通过在trx commit=2或
0时设置
innodb flush log删除耐久性保证,也会在一定程度上改善插入数。

您的innodb缓冲池大小是多少?确保已将其设置为RAM的75%。
对于InnoDB,插入通常在主键顺序下更好。但是如果池的大小很大,您应该可以看到很好的速度。

可以加快插入速度的因素:

  • 在将大数据插入空表之前,我已删除了表中的所有键
  • 然后发现我有一个问题,索引不适合内存
  • 还发现即使未使用binlog,我也有sync_binlog=0(应该是1)
  • 还发现我没有设置innodb_buffer_pool_实例

这是一个老话题,但经常被搜索。只要您意识到在大规模更新之前的最后一秒钟左右丢失已提交事务的风险(如上面@philip Koshy所述),您就可以设置这些全局参数

innodb_flush_log_at_trx_commit=0
sync_binlog=0
然后在更新完成后再打开(如果需要)

innodb_flush_log_at_trx_commit=1
sync_binlog=1
完全符合酸性要求

当这两个选项都关闭和打开时,写/更新性能会有巨大的差异。根据我的经验,上面讨论的其他东西会产生一些不同,但只是微不足道

另一个对更新/插入影响很大的因素是全文索引。在一种情况下,一个包含两个文本字段的表具有全文索引,插入2mil行需要6个小时,删除全文索引后只需10分钟。索引越多,时间越长。因此,在大量插入/更新之前,可能会删除除unique和primary key之外的搜索索引。

解决方案

  • 创建与当前主键相同的新唯一键
  • 添加新列
    id
    为无符号整数,自动递增
  • 在新的
    id
    列上创建主键

  • Bam,即时10x+插入改进。

    我添加了这个,它仍然在运行。。。我想我会在3000秒左右给你回电话,告诉你这没什么不同……;)它还在运行,所以不,这不是问题,这救了我。我不得不插入大约900万行,24小时后只完成了10%。我根据你的帖子修改为一笔交易,大约2小时就完成了!谢谢你救了我的命!:)我每秒大约有100次插入。。有了这个,我的速度是25000/秒!:)你应该会得到一枚奖牌:)>我很想看看你在这方面的基准!MyISAM:创建一个具有自动递增键的表,然后将索引添加到随机键字段,其速度大致与之前创建具有索引的随机字段的表一样快;都在8秒以下。InnoDB:使用自动递增主键插入需要54秒。然后在该随机场上创建索引需要214秒。速度很慢,但比使用随机键插入要快得多。Paul,关于顺序键的性能和好处的一般问题:只要顺序键仍然有序,它们之间是否有间隙就重要?i、 e:1、5、10、500、1234、7800等。我已经阅读了大量关于按顺序排列键的好处的材料,但我不确定“顺序排列”是指按升序排列(可能有间隙),还是顺序排列意味着没有间隙。奇怪的是,这与我正在使用的多服务器密钥生成系统有关,我在StackOverflow问题#6338956中讨论过。谢谢。随机键插入速度如此之慢的原因是InnoDB以主键顺序存储行,而不是拥有一个带有单独主键索引的巨大随机行数据池。这意味着,如果插入(仅)一条id为1的记录和另一条id为10的记录,则两行的数据将并排存储。如果然后插入id为5的记录,InnoDB ha
    innodb_flush_log_at_trx_commit=1
    sync_binlog=1