请参阅下面的更新
我有一个函数,它使用gorm查询postrgesql数据库,然后遍历返回的所有行,并执行一些简单的计算,例如检查自上次通知和价格变化以来的时间差等。
令人失望的是,每10行需要1.2秒,这是线性的,谢天谢地
所以10,000行大约需要20分钟--我测试过了--并且缩放非常线性,5,000行大约需要10分钟等等。
如何减少这种情况,以便在几秒钟内完成我想要完成的任务?我计划在1,000,000行上迭代,这是我的期望,而--我希望能够在60秒或更短的时间内完成这个任务--超过100万行
背景故事:
我最初使用python框架构建了这个应用程序,我获得了一些类似的性能,与slower...but一样,python与动态输入的python相比,速度非常快,速度也非常愚蠢,但是大约2倍的性能,真的是这样吗?
所以,现在我用golang重新构建了整个应用程序,我仍然得到了这个糟糕的数字,现在是时候向我心爱的stackoverflow社区寻求帮助了。
对于如何最好地完成这一任务,我都会听取所有的建议。就像我说的,我可以处理100万行,所以我正在寻找一种未来的证明解决方案,以及一些类似于这样做的最佳方法。
我有下面任务所做的功能,这样你们就可以确切地看到迭代中涉及到的内容。
package main
import (
...
...
...
"fmt"
"time"
)
func SendNotification() error {
var productPrices []models.ProductPrice
database.DB.Where("status = ?", "enabled").Find(&productPrices)
timeNow := time.Now()
for _, productPrice := range productPrices {
if productPrice.LastNotified.IsZero() != true {
lastNotified := productPrice.LastNotified
timeNotified, _ := time.Parse(time.RFC3339, lastNotified.String())
timeDuration := timeNow.Sub(timeNotified)
timeDurationSeconds := timeDuration.Seconds()
if uint64(timeDurationSeconds) < productPrice.Cooldown {
continue
}
}
// call an external API endpoint to get the current price of product based on product name
setPrice := providers.GetProductPrice(providers.ProviderOne, productPrice.Name)
if float64(setPrice) == 0 {
continue
}
if productPrice.Type == "above" && productPrice.Price >= float64(setPrice) {
continue
}
if productPrice.Type == "below" && productPrice.Price <= float64(setPrice) {
continue
}
var user models.User
database.DB.Where("id = ?", productPrice.UserId).First(&user)
userTo := user.Email
notificationMessage := fmt.Sprintf(`<!DOCTYPE html>
<html lang="en">
<body>
<p> Welcome back %s
</body>
</html>`, user.Email)
emailSubject := fmt.Sprintf("%s product notification for %s", productPrice.Name, user.Email)
if productPrice.NotificationMethod == "email" {
NotificationMethodEmail(SendEmail, userTo, notificationMessage, emailSubject)
}
if productPrice.NotificationMethod == "sms" {
NotificationMethodSMS(SendSMS, userTo, notificationMessage)
}
}
fmt.Println("processed this number of rows: ", len(productPrices), "\n")
return nil
}
func SendNotificationCron() {
for {
// i deally i will be running this every 2 minutes
// when am able to speed things up to less than 60 seconds
time.Sleep(30 * time.Minute)
startTime := time.Now()
SendNotification()
endTime := time.Now()
cronDuration := endTime.Sub(startTime)
fmt.Println("duration: ", cronDuration, "\n")
}
}
func main() {
go notifications.SendNotificationCron()
}
下面是测试结果
golang-task | processed this number of rows: 10
golang-task |
golang-task | duration: 1.377023066s
golang-task |
golang-task | processed this number of rows: 10
golang-task |
golang-task | duration: 1.097972596s
golang-task | prcoessed this number of rows: 4000
golang-task |
golang-task | duration: 7m59.548090252s
golang-task |
golang-task | prcoessed this number of rows: 4000
golang-task |
golang-task | duration: 7m41.425781293s
golang-task | processed this number of rows: 8000
golang-task |
golang-task | duration: 14m10.168135161s
golang-task |
golang-task | processed this number of rows: 8000
golang-task |
golang-task | duration: 16m2.544522843s
您的帮助是非常感谢的,提前谢谢。
更新:
1
问题与每行进行外部API调用的行有关。
我按照注释中的建议更新了DB查询,使之使用JOIN,但仍然需要类似的时间来完成。
因此,我决定删除外部API块,并硬编码一个浮点值,用于所有行迭代,下面是删除外部API调用部分之后得到的内容。
golang-task | prcoessed this number of rows: 1000
golang-task |
golang-task | duration: 20.645238ms
golang-task |
golang-task | prcoessed this number of rows: 1000
golang-task |
golang-task | duration: 23.839578ms
golang-task | prcoessed this number of rows: 10000
golang-task |
golang-task | duration: 252.026702ms
golang-task |
golang-task | prcoessed this number of rows: 10000
golang-task |
golang-task | duration: 234.026715ms
所以似乎问题是外部API调用部分。在这种情况下,我现在能做什么呢? 1:https://gorm.io
发布于 2022-01-27 08:40:16
您正在为每个用户进行查询。所以你的程序会因为这个而线性地减速。这个问题有一个基本的解决办法。我不知道你的数据结构,所以把这个答案作为解决问题的指南。
你必须加入到这里来:
database.DB.Where("status = ?", "enabled").Find(&productPrices)
您必须删除以下查询:
database.DB.Where("id = ?", productPrice.UserId).First(&user)
并从productPrices.User
获取数据,而不是为用户查询n次。
https://stackoverflow.com/questions/70874464
复制相似问题