从数据库分区中读取数据

huangapple go评论79阅读模式
英文:

Reading from a database partition

问题

我有以下的代码片段,用于创建并写入到一个Postgres分区:

package main

import (
	"fmt"
	"log"
	"time"

	"github.com/go-pg/pg/v10"
	"github.com/go-pg/pg/v10/orm"
)

type Log struct {
	tableName struct{} `pg:"logs,partition_by:RANGE(log_time)"`

	Id        int       `pg:"id,pk"`
	LogString string    `pg:"log_string"`
	LogTime   time.Time `pg:"log_time,pk"`
}

func main() {
	db := pg.Connect(&pg.Options{
		Addr:     "localhost:5432",
		User:     "postgres",
		Password: "postgres",
		Database: "db_name",
	})
	defer db.Close()

	/*
		The code below generates the following MySQL query

		CREATE TABLE IF NOT EXISTS "logs" (
			"id" bigserial,
			"log_string" text,
			"log_time" timestamptz,
			PRIMARY KEY ("id", "log_time")
		) PARTITION BY RANGE(log_time)
	*/
	err := db.Model(&Log{}).CreateTable(&orm.CreateTableOptions{
		IfNotExists: true,
	})

	if err != nil {
		log.Fatal(err)
	}

	logStartTime := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
	logEndTime := logStartTime.AddDate(0, 0, 3)
	for logStartTime.Unix() <= logEndTime.Unix() {
		logData := &Log{
			LogString: fmt.Sprintf("Log at %s", logStartTime.String()),
			LogTime:   logStartTime,
		}

		// before insert: always try to create partition
		err = createNewPartition(db, logStartTime)
		if err != nil {
			log.Fatal(err)
		}

		_, err = db.Model(logData).Insert()
		if err != nil {
			log.Fatal(err)
		}
		logStartTime = logStartTime.AddDate(0, 0, 1)
	}
}

// createNewPartition will create new partition of logs table if not exist.
// Partition created by in one month range start from first date of the month to last date of the month.
func createNewPartition(db *pg.DB, currentTime time.Time) error {
	firstOfMonth := time.Date(currentTime.Year(), currentTime.Month(), 1, 0, 0, 0, 0, time.UTC)
	firstOfNextMonth := firstOfMonth.AddDate(0, 1, 0)

	year := firstOfMonth.Format("2006")
	month := firstOfMonth.Format("01")
	sql := fmt.Sprintf(
		`CREATE TABLE IF NOT EXISTS logs_y%s_m%s PARTITION OF logs FOR VALUES FROM ('%s') TO ('%s');`,
		year, month,
		firstOfMonth.Format(time.RFC3339Nano),
		firstOfNextMonth.Format(time.RFC3339Nano),
	)

	log.Println("Creating partition ", sql)

	_, err := db.Exec(sql)
	return err
}

func readFromPartition(db *pg.DB) error {
	return nil
}

然而,我想要实现readFromPartition方法...它应该是什么样子的?我能够从每个分区中读取吗?给定一个数据日志,我想要在正确的分区中进行查询。

英文:

I have the following code snippet that creates and writes to a Postgres Partition:

package main
import (
&quot;fmt&quot;
&quot;log&quot;
&quot;time&quot;
&quot;github.com/go-pg/pg/v10&quot;
&quot;github.com/go-pg/pg/v10/orm&quot;
)
type Log struct {
tableName struct{} `pg:&quot;logs,partition_by:RANGE(log_time)&quot;`
Id        int       `pg:&quot;id,pk&quot;`
LogString string    `pg:&quot;log_string&quot;`
LogTime   time.Time `pg:&quot;log_time,pk&quot;`
}
func main() {
db := pg.Connect(&amp;pg.Options{
Addr:     &quot;localhost:5432&quot;,
User:     &quot;postgres&quot;,
Password: &quot;postgres&quot;,
Database: &quot;db_name&quot;,
})
defer db.Close()
/*
The code below generates the following MySQL query
CREATE TABLE IF NOT EXISTS &quot;logs&quot; (
&quot;id&quot; bigserial,
&quot;log_string&quot; text,
&quot;log_time&quot; timestamptz,
PRIMARY KEY (&quot;id&quot;, &quot;log_time&quot;)
) PARTITION BY RANGE(log_time)
*/
err := db.Model(&amp;Log{}).CreateTable(&amp;orm.CreateTableOptions{
IfNotExists: true,
})
if err != nil {
log.Fatal(err)
}
logStartTime := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
logEndTime := logStartTime.AddDate(0, 0, 3)
for logStartTime.Unix() &lt;= logEndTime.Unix() {
logData := &amp;Log{
LogString: fmt.Sprintf(&quot;Log at %s&quot;, logStartTime.String()),
LogTime:   logStartTime,
}
// before insert: always try to create partition
err = createNewPartition(db, logStartTime)
if err != nil {
log.Fatal(err)
}
_, err = db.Model(logData).Insert()
if err != nil {
log.Fatal(err)
}
logStartTime = logStartTime.AddDate(0, 0, 1)
}
}
// createNewPartition will create new partition of logs table if not exist.
// Partition created by in one month range start from first date of the month to last date of the month.
func createNewPartition(db *pg.DB, currentTime time.Time) error {
firstOfMonth := time.Date(currentTime.Year(), currentTime.Month(), 1, 0, 0, 0, 0, time.UTC)
firstOfNextMonth := firstOfMonth.AddDate(0, 1, 0)
year := firstOfMonth.Format(&quot;2006&quot;)
month := firstOfMonth.Format(&quot;01&quot;)
sql := fmt.Sprintf(
`CREATE TABLE IF NOT EXISTS logs_y%s_m%s PARTITION OF logs FOR VALUES FROM (&#39;%s&#39;) TO (&#39;%s&#39;);`,
year, month,
firstOfMonth.Format(time.RFC3339Nano),
firstOfNextMonth.Format(time.RFC3339Nano),
)
log.Println(&quot;Creating partition &quot;, sql)
_, err := db.Exec(sql)
return err
}
func readFromPartition(db *pg.DB) error {
return nil
}

However, I want to to implement the method readFromPartition... what would look like? Can I read from each partition? Given a data log, I want to query in the right partition.

答案1

得分: 1

要从正确的分区中读取数据,您需要根据LogTime确定数据所在的分区,然后可以使用pg.Query和pg.Model函数构造一个指定适当分区的查询。以下是readFromPartition函数的实现,它根据给定的logTime检索日志条目:

func readFromPartition(db *pg.DB, logTime time.Time) ([]Log, error) {
    firstOfMonth := time.Date(logTime.Year(), logTime.Month(), 1, 0, 0, 0, 0, time.UTC)
    year := firstOfMonth.Format("2006")
    month := firstOfMonth.Format("01")

    partitionName := fmt.Sprintf("logs_y%s_m%s", year, month)

    var logs []Log
    err := db.Model(&logs).TableExpr(partitionName).Where("log_time >= ? AND log_time < ?", logTime, logTime.Add(24*time.Hour)).Select()
    if err != nil {
        return nil, err
    }

    return logs, nil
}

以下是如何使用readFromPartition函数读取日志的示例代码:

func main() {
    // ... (现有代码)

    logStartTime := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
    logEndTime := logStartTime.AddDate(0, 0, 3)
    for logStartTime.Unix() <= logEndTime.Unix() {
        // ... (现有代码)
        logStartTime = logStartTime.AddDate(0, 0, 1)
    }

    // 读取特定日期的日志
    logs, err := readFromPartition(db, time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC))
    if err != nil {
        log.Fatal(err)
    }

    for _, logData := range logs {
        fmt.Println(logData.LogString, logData.LogTime)
    }
}

这段代码将从与指定logTime对应的分区中读取日志。如果给定日期的分区中有任何日志,它将打印它们。

英文:

To read from the correct partition, you'll need to determine which partition the data resides in based on the LogTime. Then, you can construct a query that specifies the appropriate partition using the pg.Query and pg.Model functions. Here's an implementation of the readFromPartition function that retrieves log entries based on a given logTime:

func readFromPartition(db *pg.DB, logTime time.Time) ([]Log, error) {
firstOfMonth := time.Date(logTime.Year(), logTime.Month(), 1, 0, 0, 0, 0, time.UTC)
year := firstOfMonth.Format(&quot;2006&quot;)
month := firstOfMonth.Format(&quot;01&quot;)
partitionName := fmt.Sprintf(&quot;logs_y%s_m%s&quot;, year, month)
var logs []Log
err := db.Model(&amp;logs).TableExpr(partitionName).Where(&quot;log_time &gt;= ? AND log_time &lt; ?&quot;, logTime, logTime.Add(24*time.Hour)).Select()
if err != nil {
return nil, err
}
return logs, nil
}

Here's how to use the readFromPartition function to read logs:

func main() {
// ... (existing code)
logStartTime := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
logEndTime := logStartTime.AddDate(0, 0, 3)
for logStartTime.Unix() &lt;= logEndTime.Unix() {
// ... (existing code)
logStartTime = logStartTime.AddDate(0, 0, 1)
}
// Read logs for a specific date
logs, err := readFromPartition(db, time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC))
if err != nil {
log.Fatal(err)
}
for _, logData := range logs {
fmt.Println(logData.LogString, logData.LogTime)
}
}

This code will read logs from the partition that corresponds to the specified logTime. If there are any logs in the partition for the given date, it will print them.

huangapple
  • 本文由 发表于 2023年4月17日 09:57:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76031249.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定