jjzjj

c++ - 使用相同的 golang 片段查询 mysql 数据库的巨大性能差异

coder 2024-07-11 原文

我最近用 golang 重新实现了我的项目。该项目是用 C++ 实现的。当我完成代码并进行性能测试时。我对结果感到震惊。当我用 C++ 查询数据库时,我可以在 5 分钟内得到 1.3 亿行结果。但是对于 golang,它几乎是 45 分钟。但是当我将代码从项目中分离出来并构建代码片段时,它会在 2 分钟内完成。为什么它们的性能结果会有如此巨大的差异?

我的代码片段: https://gist.github.com/pyanfield/2651d23311901b33c5723b7de2364148

package main

import (
    "database/sql"
    "fmt"
    "runtime"
    "strconv"
    "time"

    _ "github.com/go-sql-driver/mysql"
)

func main() {
    runtime.GOMAXPROCS(runtime.NumCPU())
    // defer profile.Start(profile.CPUProfile, profile.ProfilePath(".")).Stop()
    dbRead, err := connectDB("test:test@tcp(127.0.0.1:3306)/test_oltp?charset=utf8&readTimeout=600s&writeTimeout=600s")
    if err != nil {
        fmt.Printf("Error happend when connecting to DB. %s\n", err.Error())
        return
    }
    defer dbRead.Close()
    dbRead.SetMaxIdleConns(0)
    dbRead.SetMaxOpenConns(100)

    query := fmt.Sprintf("WHERE company_id in (11,22,33,44,55,66,77,88,99,00,111,222,333,4444,555,666,777,888,999)")

    relations := getRelations(dbRead, query)
}
func connectDB(addr string) (*sql.DB, error) {
    db, err := sql.Open("mysql", addr)
    if err != nil {
        return nil, err
    }
    if err = db.Ping(); err != nil {
        return nil, err
    }
    return db, nil
}

type Relation struct {
    childId  int64 
    parentId int64 
}

func getRelations(db *sql.DB, where string)[]Relation {
    begin := time.Now()

    var err error
    var rows *sql.Rows
    query := fmt.Sprintf("SELECT `child_id`, `parent_id` FROM `test_relations` %s", where)
    rows, err = db.Query(query)
    if err != nil {
        fmt.Println("query error:", err.Error())
        return nil
    }
    defer rows.Close()

    columns, err := rows.Columns()
    buffer := make([]sql.RawBytes, len(columns))
    scanArgs := make([]interface{}, len(buffer))
    for i := range scanArgs {
        scanArgs[i] = &buffer[i]
    }

    relations := []Relation{}
    relation := Relation{}
    for rows.Next() {
        if err = rows.Scan(scanArgs...); err != nil {
            fmt.Println("scan:", err.Error())
            return nil
        }
        relation.parentId, _ = strconv.ParseInt(string(buffer[1]), 10, 64)
        relation.childId, _ = strconv.ParseInt(string(buffer[0]), 10, 64)

        relations = append(relations, relation)
    }

    if err = rows.Err(); err != nil {
        fmt.Println("next error:", err.Error())
        return nil
    }
    fmt.Printf(">>> getRelations cost: %s\n", time.Since(begin).String())
    // output :>>> getRelations cost:1m45.791047s
    return relations
    // len(relations): 131123541
}

更新: 我的go版本是1.6。我得到的cpu配置文件如下: 代码段简介top20:

    75.67s of 96.82s total (78.16%)
Dropped 109 nodes (cum <= 0.48s)
Showing top 20 nodes out of 82 (cum >= 12.04s)
      flat  flat%   sum%        cum   cum%
    11.85s 12.24% 12.24%     11.85s 12.24%  runtime.memmove
    10.28s 10.62% 22.86%     20.01s 20.67%  runtime.mallocgc
     5.82s  6.01% 28.87%      5.82s  6.01%  strconv.ParseUint
     5.79s  5.98% 34.85%      5.79s  5.98%  runtime.futex
     3.42s  3.53% 38.38%     10.28s 10.62%  github.com/go-sql-driver/mysql.(*buffer).readNext
     3.42s  3.53% 41.91%      6.38s  6.59%  runtime.scang
     3.37s  3.48% 45.39%     36.97s 38.18%  github.com/go-sql-driver/mysql.(*textRows).readRow
     3.37s  3.48% 48.87%      3.37s  3.48%  runtime.memclr
     3.20s  3.31% 52.18%      3.20s  3.31%  runtime.heapBitsSetType
     3.02s  3.12% 55.30%      7.36s  7.60%  database/sql.convertAssign
     2.96s  3.06% 58.36%      3.02s  3.12%  runtime.(*mspan).sweep.func1
     2.53s  2.61% 60.97%      2.53s  2.61%  runtime._ExternalCode
     2.39s  2.47% 63.44%      2.96s  3.06%  runtime.readgstatus
     2.24s  2.31% 65.75%      8.06s  8.32%  strconv.ParseInt
     2.21s  2.28% 68.03%      5.24s  5.41%  runtime.heapBitsSweepSpan
     2.15s  2.22% 70.25%      7.68s  7.93%  runtime.rawstring
     2.06s  2.13% 72.38%      3.18s  3.28%  github.com/go-sql-driver/mysql.readLengthEncodedString
     1.95s  2.01% 74.40%     12.23s 12.63%  github.com/go-sql-driver/mysql.(*mysqlConn).readPacket
     1.83s  1.89% 76.29%     79.42s 82.03%  main.Relations
     1.81s  1.87% 78.16%     12.04s 12.44%  runtime.slicebytetostring

项目cpu配置文件top20:

     (pprof) top20
38.71mins of 42.82mins total (90.40%)
Dropped 334 nodes (cum <= 0.21mins)
Showing top 20 nodes out of 76 (cum >= 1.35mins)
      flat  flat%   sum%        cum   cum%
 12.02mins 28.07% 28.07%  12.48mins 29.15%  runtime.addspecial
  5.95mins 13.89% 41.96%  15.08mins 35.21%  runtime.pcvalue
  5.26mins 12.29% 54.25%   5.26mins 12.29%  runtime.readvarint
  2.60mins  6.08% 60.32%   7.87mins 18.37%  runtime.step
  1.98mins  4.62% 64.94%  19.45mins 45.43%  runtime.gentraceback
  1.65mins  3.86% 68.80%   1.65mins  3.86%  runtime/internal/atomic.Xchg
  1.57mins  3.66% 72.46%   2.93mins  6.84%  runtime.(*mspan).sweep
  1.52mins  3.54% 76.01%   1.78mins  4.15%  runtime.findfunc
  1.41mins  3.30% 79.31%   1.42mins  3.31%  runtime.markrootSpans
  1.13mins  2.64% 81.95%   1.13mins  2.64%  runtime.(*fixalloc).alloc
  0.64mins  1.50% 83.45%   0.64mins  1.50%  runtime.duffcopy
  0.46mins  1.08% 84.53%   0.46mins  1.08%  runtime.findmoduledatap
  0.44mins  1.02% 85.55%   0.44mins  1.02%  runtime.fastrand1
  0.42mins  0.97% 86.52%  15.49mins 36.18%  runtime.funcspdelta
  0.38mins  0.89% 87.41%  36.02mins 84.13%  runtime.mallocgc
  0.30mins   0.7% 88.12%   0.78mins  1.83%  runtime.scanobject
  0.26mins   0.6% 88.72%   0.32mins  0.74%  runtime.stkbucket
  0.26mins   0.6% 89.32%   0.26mins   0.6%  runtime.memmove
  0.23mins  0.55% 89.86%   0.23mins  0.55%  runtime.heapBitsForObject
  0.23mins  0.53% 90.40%   1.35mins  3.15%  runtime.lock

最佳答案

我得到了答案并想分享它。这是我的错误造成的。以前有时,我尝试添加内存配置文件并设置 运行时。 MemProfileRate=1 在我的 init 方法中。但是我忘了把它重置为一个合理的值。我每次检查代码时都忽略了这个方法。从我的项目中删除此设置后,它恢复正常,并且花了将近 5~6 分钟来查询这 130M 数据。速度非常接近 C++ 版本。我的建议是,除非您确定要这样做,否则在设置 runtime.MemProfileRate=1 时请小心,并记得将其重置。

关于c++ - 使用相同的 golang 片段查询 mysql 数据库的巨大性能差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37500878/

有关c++ - 使用相同的 golang 片段查询 mysql 数据库的巨大性能差异的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - ECONNRESET (Whois::ConnectionError) - 尝试在 Ruby 中查询 Whois 时出错 - 2

    我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.

  10. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

随机推荐