source

Go-SQL-Driver로 인해 maria-db CPU 사용률이 매우 높음

nicesource 2023. 9. 21. 20:34
반응형

Go-SQL-Driver로 인해 maria-db CPU 사용률이 매우 높음

웹사이트와 앱의 백엔드를 위해 파이썬 플라스크에 작성한 API가 있었는데 잘 작동합니다.최근에 바둑을 배워서 전체 API를 바둑으로 다시 썼습니다.Go 바이너리 파일에서 CPU와 메모리 활용률이 훨씬 낮아질 것으로 예상했지만 MariaDB는 이제 거의 99%의 활용률을 기록했습니다.

나는 GitHub 페이지에서 max connection, max timeout, maxidle time, max... 등의 all 옵션을 제한하려고 노력하지만 여전히 소용이 없습니다.코드의 글로벌 변수로 연결되어 있고, 저는 연기합니다.result.close()결국은db.prepare그리고.db.query. 바둑이 파이썬보다 훨씬 빠르다는 것을 알고 있으므로 서버에 더 많은 요청을 하는 것이 합리적이지만 유일한 테스트 환경이므로 골랑에서 마리아DB를 처리하는 방법에 대한 제안이 있습니까?

참고: 2015년부터 작동하는 원래 사이트에는 적어도 백만 행 이상의 데이터가 있습니다. 곰을 사용하여 데이터베이스를 재생성하고 데이터를 다시 삽입할 수 있지만 순수 SQL을 사용하고 싶습니다(ORM 감사합니다).

func getfulldate(c *fiber.Ctx) error {

    pid := c.FormValue("pid")

    result, err := db.Prepare("select concat(p.firstName, ' ', p.middle, ' ', p.lastName, ' ', p.forthName) as fullname,gender,bID,married,barcode,comment,address,if(p2.phone is null, 0, p2.phone)  as phone,rName,occupation,weight,height,cast(Birthdate as date) as Birthdate from profile p left join (select phID, pID, phone from phonefix group by pID) p2 on p.pID = p2.pID left join (select pID, weight, height from bmifix group by pID) B on p.pID = B.pID, religion r where r.rgID = p.rgID and p.pID = ? ")
    defer result.Close()
    if err != nil {
        return c.JSON(fiber.Map{"access_token": "wrong"})

    }

    rows, err := result.Query(pid)
    defer rows.Close()
    if err != nil {
        return c.JSON(fiber.Map{"access_token": "wrong"})

    }
    columns, err := rows.Columns()
    if err != nil {
        return err
    }
    count := len(columns)
    tableData := make([]map[string]interface{}, 0)
    values := make([]interface{}, count)
    valuePtrs := make([]interface{}, count)
    for rows.Next() {
        for i := 0; i < count; i++ {
            valuePtrs[i] = &values[i]
        }
        rows.Scan(valuePtrs...)
        entry := make(map[string]interface{})
        for i, col := range columns {
            var v interface{}
            val := values[i]
            b, ok := val.([]byte)
            if ok {
                v = string(b)
            } else {
                v = val
            }
            entry[col] = v
        }
        tableData = append(tableData, entry)
    }

    currentTime := time.Now().Format("2006-01-02")
    result, err = db.Prepare("select viID,state as done,dob from visitfix where  patientID = ?")
    defer result.Close()
    if err != nil {
        return c.JSON(fiber.Map{"access_token": "wrong"})

    }

    rows, err = result.Query(pid)
    defer rows.Close()
    if err != nil {
        return c.JSON(fiber.Map{"access_token": "wrong"})

    }
    columns = []string{"viID", "done", "dob"}

    count = len(columns)
    tableDatas := make([]map[string]interface{}, 0)
    values = make([]interface{}, count)
    valuePtrs = make([]interface{}, count)
    for rows.Next() {
        for i := 0; i < count; i++ {

            valuePtrs[i] = &values[i]
        }

        rows.Scan(valuePtrs...)

        entry := make(map[string]interface{})

        for i, col := range columns {
            var v interface{}
            val := values[i]

            b, ok := val.([]byte)

            if ok {
                v = string(b)
            } else {
                v = val
            }
            if i == 2 {
                var state string
                format := "2006-1-2"

                datea, err := time.Parse(format, string(b))
                if err != nil {
                    return err
                }
                mydate := datea.Format("2006-01-02")
                if mydate == currentTime {
                    state = "today"
                }
                if mydate < currentTime {
                    state = "older"
                }
                if mydate > currentTime {
                    state = "newer"
                }

                entry["state"] = state

            }

            entry[col] = v
        }

        tableDatas = append(tableDatas, entry)
    }
    alldata := [][]map[string]interface{}{tableData, tableDatas}
    dat, err := json.Marshal(alldata)
    if err != nil {
        return err
    }

    return c.SendString(string(dat))
}

행 데이터를 검색하기 위한 더 나은 드라이버 구현을 금지하는 다른 언어(MySQL의 커서 구현이 중단되었을 수도 있음)와 마찬가지로 이동 프로세스 자체가 데이터베이스에 다른 영향을 미치지 않아야 합니다.

커서 사용에 관해서는 다음과 같습니다.이렇게 하면 부하가 더 오래 걸릴 수 있지만 드라이버 구현과 언어 간의 차이를 파악하려면 상당한 양의 데이터가 필요합니다.컴파일된 언어들은 그 시점에서 DB에 더 높은 부하를 가할 수 있을 것입니다.하지만 다시 한 번:이런 경우는 드물 것입니다.

여기서 살펴볼 주요 후보는 색인일 가능성이 높습니다.쿼리 중:

    result, err := db.Prepare(`select concat(p.firstName, ' ', p.middle, ' ', p.lastName, ' ', p.forthName) 
as fullname,gender,bID,married,barcode,comment,address,if(p2.phone is null, 0, p2.phone)  
as phone,rName,occupation,weight,height,cast(Birthdate as date) as Birthdate 
from profile p 
left join (select phID, pID, phone from phonefix group by pID) p2 on p.pID = p2.pID 
left join (select pID, weight, height from bmifix group by pID) B on p.pID = B.pID, religion r 
where r.rgID = p.rgID and p.pID = ? `)

p.p.에 인덱스를 사용하길 원하십니까?ID, r.rgID 그리고 p.rgID.그러면 왼쪽 조인의 pID별 그룹도 최적이 아닌 방법으로 실행될 수 있습니다(설명을 실행하고 실행 계획을 확인합니다.

다음 문장을 통해 그룹을 제거하는 것도 개선할 수 있습니다.함수별 그룹이 없으므로 왼쪽에 있는 그룹은 사용할 수 없습니다.

    result, err := db.Prepare(`select concat(p.firstName, ' ', p.middle, ' ', p.lastName, ' ', p.forthName) 
as fullname,gender,bID,married,barcode,comment,address,if(p2.phone is null, 0, p2.phone)  
as phone,rName,occupation,weight,height,cast(Birthdate as date) as Birthdate 
from profile p 
left join (select phID, pID, phone from phonefix) p2 on p.pID = p2.pID 
left join (select pID, weight, height from bmifix) B on p.pID = B.pID
left join religion r 
where r.rgID = p.rgID and p.pID = ? `)

항상 단일 pID를 검색하는 것이 고유한 레코드로 보이므로 다음이 더 나을 수 있습니다(테스트할 수 없음).DB 없음 :): 가능한 경우 내부 조인으로 이동합니다.그것은 왼쪽 조인보다 성능이 뛰어날 것입니다.

언급URL : https://stackoverflow.com/questions/73101963/go-sql-driver-causing-maria-db-cpu-utilization-very-high

반응형