Open utterances-bot opened 2 years ago
我们也在用 sqlc,原因有几个:
但是 sqlc 确实不太成熟,问题比较多,期待更好的工具
关于用 ORM 或者 SQL Builder debug 不方便的问题, 有两个办法可以缓解, 当然只是缓解:
直接写sql灵活方便,性能好,查错也快
java的mybatis了解下,golang好像也有类似的实现。
这个厉害啊
java的mybatis了解下,golang好像也有类似的实现。
Go 之前有一个,不过 Go 不像 java 那样能在注解里搞花活儿,写在注释里的东西说到底不是一个特别强的约束
我们也在用 sqlc,原因有几个:
- ORM 性能太差
- ORM 使得开发者不知道写出什么 SQL
- 直接用 database/sql 或者 sql builder 写起来比较痛苦
但是 sqlc 确实不太成熟,问题比较多,期待更好的工具
我这边也还在调研,sqlc 除了对 mysql 支持不太好(比如不支持 in),还有啥问题么?
我这边也还在调研,sqlc 除了对 mysql 支持不太好(比如不支持 in),还有啥问题么?
本来觉得facebook的ent还不错的,看来也被曹大否了
本来觉得facebook的ent还不错的,看来也被曹大否了
也没完全否定 orm,tob 场景 orm 并发量不高,或者公司内部平台 orm 挺好的,写着方便
主要是 toc 的 db 挂了影响面太大,得做事前预防,所以得搞这种 sql 方案
所以如果清楚的知道 ORM 会搞出来什么代码就没有问题咯 个人觉得代码还是语义化更好一些诶...毕竟是代码是给人读的,不是给机器读的,私以为牺牲一点点性能(非 DB 层)换来可读性的提高是划得来的 另外小声比比一下...我个人从 PHP 划到 GO,然后发现这语言哪有什么好用的 ORM 呀...
说实话Go的ORM甚至没有到好用的地步,还是sqlx或者sqlc写起来更舒服,但是可惜sqlc对MySQL支持不太完美
期待曹大的轮子
所以如果清楚的知道 ORM 会搞出来什么代码就没有问题咯 个人觉得代码还是语义化更好一些诶...毕竟是代码是给人读的,不是给机器读的,私以为牺牲一点点性能(非 DB 层)换来可读性的提高是划得来的 另外小声比比一下...我个人从 PHP 划到 GO,然后发现这语言哪有什么好用的 ORM 呀...
自己的项目怎么都顺手,接手别人的找不着sql还是令人懊恼
看到这里,深有感触,我司主要是java dubbo微服务,目前的sql审核做法是,通过匹配代码关键字,找到apollo namespace,一个namespace对应一个mysql数据源,然后解析mybatis xml文件,生成sql,然后用小米开源的soar进行sql审核,进行预执行,不过效果还是差点,主要是当一个项目中用到的数据源比较多时候,自动匹配数据源不太容易做到,最近还在想办法优化,有些sql因为生产环境qps,不会有什么问题,但是生产出现就很致命了,比如qps很高时候insert table on duplicate key update会导致死锁 soar mybatis-mapper2sql
看到这里,深有感触,我司主要是java dubbo微服务,目前的sql审核做法是,通过匹配代码关键字,找到apollo namespace,一个namespace对应一个mysql数据源,然后解析mybatis xml文件,生成sql,然后用小米开源的soar进行sql审核,进行预执行,不过效果还是差点,主要是当一个项目中用到的数据源比较多时候,自动匹配数据源不太容易做到,最近还在想办法优化,有些sql因为生产环境qps,不会有什么问题,但是生产出现就很致命了,比如qps很高时候insert table on duplicate key update会导致死锁 soar mybatis-mapper2sql
你们已经做的很好啦哈哈
可以试下我的sqlw,也是主张raw sql,不需要像sqlc那样去生成一大坨代码,只需要自己声明结构体这些,也不需要像直接使用标准库那样自己去for循环绑定。相比于sqlc,sqlw处理绑定时肯定是需要一些结构体反射的操作所以性能不如sqlc,但不必ORM性能更差,而且对于数据库操作、这点损失不算什么。 sqlw常规用法:
package main
import (
"log"
_ "github.com/go-sql-driver/mysql"
"github.com/lesismal/sqlw"
)
const (
sqlDropDatabase = `drop database if exists sqlw_test`
sqlCreateDatabase = `create database sqlw_test`
sqlDropTable = `drop table if exists sqlw_test.sqlw_test`
sqlCreateTable = `
create table sqlw_test.sqlw_test (
id bigint primary key auto_increment,
i bigint not null default 0,
s varchar(64) not null default ''
)`
)
type Model struct {
Id int64 `db:"id"`
I int64 `db:"i"`
S string `db:"s"`
}
func main() {
db, err := sqlw.Open("mysql", "test:123qwe@tcp(localhost:3306)/mysql", "db")
if err != nil {
log.Fatalf("sqlw.Open failed: %v", err)
}
_, err = db.Exec(sqlCreateDatabase)
if err != nil {
log.Panic(err)
}
defer db.Exec(sqlDropDatabase)
_, err = db.Exec(sqlCreateTable)
if err != nil {
log.Panic(err)
}
defer db.Exec(sqlDropTable)
model := &Model{
I: 1,
S: "str_1",
}
result, err := db.Insert("insert into sqlw_test.sqlw_test", model)
// result, err := db.Insert("insert into sqlw_test.sqlw_test(i,s)", &model) // insert the specified fields
if err != nil {
log.Fatalf("db.Insert failed: %v", err)
}
// print sql for debug
log.Println("Insert sql:", result.Sql())
var ret Model
result, err = db.Select(&ret, "select * from sqlw_test.sqlw_test where id=?", 1)
// result, err := db.Select(&model, "select (i,s) from sqlw_test.sqlw_test where id=?", selectId) // select the specified fields
if err != nil {
log.Fatalf("db.Select failed: %v", err)
}
log.Println("ret:", ret)
// print sql for debug
log.Println("Select sql:", result.Sql())
newModel := &Model{
I: 10,
S: "str_10",
}
result, err = db.Update("update sqlw_test.sqlw_test set i=?, s=? where id=?", newModel, 1)
if err != nil {
log.Fatalf("db.Update failed: %v", err)
}
// print sql for debug
log.Println("Update sql:", result.Sql())
result, err = db.Delete("delete from sqlw_test.sqlw_test where id=?", 10)
if err != nil {
log.Fatalf("db.Delete failed: %v", err)
}
// print sql for debug
log.Println("Delete sql:", result.Sql())
}
可以试下我的sqlw,也是主张raw sql,不需要像sqlc那样去生成一大坨代码,只需要自己声明结构体这些,也不需要像直接使用标准库那样自己去for循环绑定。相比于sqlc,sqlw处理绑定时肯定是需要一些结构体反射的操作所以性能不如sqlc,但不必ORM性能更差,而且对于数据库操作、这点损失不算什么。 sqlw常规用法:
package main import ( "log" _ "github.com/go-sql-driver/mysql" "github.com/lesismal/sqlw" ) const ( sqlDropDatabase = `drop database if exists sqlw_test` sqlCreateDatabase = `create database sqlw_test` sqlDropTable = `drop table if exists sqlw_test.sqlw_test` sqlCreateTable = ` create table sqlw_test.sqlw_test ( id bigint primary key auto_increment, i bigint not null default 0, s varchar(64) not null default '' )` ) type Model struct { Id int64 `db:"id"` I int64 `db:"i"` S string `db:"s"` } func main() { db, err := sqlw.Open("mysql", "test:123qwe@tcp(localhost:3306)/mysql", "db") if err != nil { log.Fatalf("sqlw.Open failed: %v", err) } _, err = db.Exec(sqlCreateDatabase) if err != nil { log.Panic(err) } defer db.Exec(sqlDropDatabase) _, err = db.Exec(sqlCreateTable) if err != nil { log.Panic(err) } defer db.Exec(sqlDropTable) model := &Model{ I: 1, S: "str_1", } result, err := db.Insert("insert into sqlw_test.sqlw_test", model) // result, err := db.Insert("insert into sqlw_test.sqlw_test(i,s)", &model) // insert the specified fields if err != nil { log.Fatalf("db.Insert failed: %v", err) } // print sql for debug log.Println("Insert sql:", result.Sql()) var ret Model result, err = db.Select(&ret, "select * from sqlw_test.sqlw_test where id=?", 1) // result, err := db.Select(&model, "select (i,s) from sqlw_test.sqlw_test where id=?", selectId) // select the specified fields if err != nil { log.Fatalf("db.Select failed: %v", err) } log.Println("ret:", ret) // print sql for debug log.Println("Select sql:", result.Sql()) newModel := &Model{ I: 10, S: "str_10", } result, err = db.Update("update sqlw_test.sqlw_test set i=?, s=? where id=?", newModel, 1) if err != nil { log.Fatalf("db.Update failed: %v", err) } // print sql for debug log.Println("Update sql:", result.Sql()) result, err = db.Delete("delete from sqlw_test.sqlw_test where id=?", 10) if err != nil { log.Fatalf("db.Delete failed: %v", err) } // print sql for debug log.Println("Delete sql:", result.Sql()) }
sqlc 能够在照顾强类型约束流程的前提下,做到任意 sql 上线前的审计,你这个不太行
sqlc 能够在照顾强类型约束流程的前提下,做到任意 sql 上线前的审计,你这个不太行
审计是指sqlc自己解析sql语句的时候自带了审计?如果是指这个,那sqlw确实没有
对于raw sql,我们团队审计流程通常是开发自审、审计平台+dba审,复杂的还要单独会议多工种评审。 单独靠sql语句的分析、审计平台这些自动进行审计也是不足够可靠的,性能敏感的场景需要人工,而且还要加适当的测试,不敢让审计平台上自动流程就上限 我这个也是raw sql,所以语句都是可见,这种审计流程不是问题
sqlc 能够在照顾强类型约束流程的前提下,做到任意 sql 上线前的审计,你这个不太行
审计是指sqlc自己解析sql语句的时候自带了审计?如果是指这个,那sqlw确实没有
对于raw sql,我们团队审计流程通常是开发自审、审计平台+dba审,复杂的还要单独会议多工种评审。 单独靠sql语句的分析、审计平台这些自动进行审计也是不足够可靠的,性能敏感的场景需要人工,而且还要加适当的测试,不敢让审计平台上自动流程就上限 我这个也是raw sql,所以语句都是可见,这种审计流程不是问题
人工就太 low 了,要 sql parser 把 sql 扫出来,和 information schema 和 sys 库这些里的 index 信息去做匹配的,都是很基本的东西了
人工就太 low 了,要 sql parser 把 sql 扫出来,和 information schema 和 sys 库这些里的 index 信息去做匹配的,都是很基本的东西了
所以自动审直接能搞定所有sql性能问题吗?求方案推荐,我目前还没用到过这么高级的自动审,大表海量数据我们都还是要人工加持,审核平台只做基本的分析审核
sqlc可以直接审出、搞定大表性能问题吗?
我猜sqlc或者你说的index信息去做匹配的这些,也没办法做大线上大表数据量级、线上真实并发量的真实评估吧?未来要是AI加持了我倒是相信有这么一天。 现阶段的审核平台,不人工加持一道,我是不敢允许大表或者复杂sql的上线
我猜sqlc或者你说的index信息去做匹配的这些,也没办法做大线上大表数据量级、线上真实并发量的真实评估吧?未来要是AI加持了我倒是相信有这么一天。 现阶段的审核平台,不人工加持一道,我是不敢允许大表或者复杂sql的上线
可以的。。。云厂商的 db 专家系统就是干这个的
那也不是它sqlc直接能干吧。。。不还是得sql语句本身吗。。。
关于从SQL反查链路这个case,可以往sql comment里注入trace_id
关于从SQL反查链路这个case,可以往sql comment里注入trace_id
很 6
作为DBA写出这样的文章一点都不稀奇,不干研发的活就不会从软件工程的角度考虑问题。
软件开发最重要的是封装和重用,SQL作为静态文本语言,一条SQL语句只能代表一种查询需求。遇到多个查询条件需要按照用户传参进行拼接的话,是不可能把所有组合出的SQL语句写代码里的,为了代码复用会用if语句拼接需要的查询条件,所以即使不用ORM和SQL Builder,也不可能直接搜到完整的SQL。 另外,调用复杂的情况下,即使代码里存在一模一样的SQL语句,也是需要查看代码寻找调用出处的。
DBA不写代码,不懂里面的因果关系,就把问题在于 slow query 中的 SQL 很难与代码直接关联起来
这样的问题归因到ORM和SQL builder,显然是没把原因搞清楚。
遇到慢SQL还是把SQL打到日志里去,通过测试用例覆盖去找SQL语句,而不是开历史倒车,怪到ORM和Builder上。
为什么要旗帜鲜明地反对 orm 和 sql builder
http://xargin.com/you-should-avoid-orm-and-sql-builder/