英文:
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 (
"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
}
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("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
}
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() <= 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论