Ent 是一个强大的实体框架,可帮助开发者编写简洁的代码,这些代码会被转换为(可能复杂的)数据库查询。随着应用程序使用量的增长,很快你就会遇到数据库性能问题。 排查数据库性能问题 notoriously 困难,尤其是在没有合适工具的情况下。
以下示例展示了 Ent 查询代码如何转换为 SQL 查询。

示例 1 - ent 代码被转换为 SQL 查询
传统上,将性能低下的数据库查询与生成它们的应用程序代码关联起来一直非常困难。数据库性能分析工具可以通过分析数据库服务器日志来指出慢查询,但如何将它们追溯回应用程序呢?
Sqlcommenter
今年早些时候,Google 推出了 Sqlcommenter。Sqlcommenter 是
一个开源库,旨在弥合 ORM 库与理解数据库性能之间的差距。Sqlcommenter 让应用开发者能够洞察哪些应用程序代码生成了慢查询,并将应用追踪与数据库查询计划映射起来
换句话说,Sqlcommenter 向 SQL 查询添加了应用程序上下文元数据。这些信息随后可用于提供有意义的洞察。它通过向查询添加 SQL 注释来实现这一点,这些注释携带元数据,但在查询执行期间会被数据库忽略。
例如,以下查询包含一个注释,该注释携带了有关发起查询的应用程序(users-mgr)、触发查询的控制器和路由(分别为 users 和 user_rename)以及所使用的数据库驱动程序(ent:v0.9.1)的元数据:
update users set username = ‘hedwigz’ where id = 88
/*application='users-mgr',controller='users',route='user_rename',db_driver='ent:v0.9.1'*/
要体验从 Sqlcommenter 元数据收集的分析如何帮助我们更好地理解应用程序的性能问题,请考虑以下示例:Google Cloud 最近推出了 Cloud SQL Insights,这是一个基于云的 SQL 性能分析产品。在下图中,我们看到 Cloud SQL Insights 仪表板的截图,显示 HTTP 路由 'api/users' 正在数据库上引发许多锁。我们还可以看到,在过去 6 小时内该查询被调用了 16,067 次。

Cloud SQL Insights 仪表板截图
这就是 SQL 标签的力量——它们提供了应用程序级信息与数据库监视器之间的关联。
sqlcomment
sqlcomment 是一个 Ent 驱动程序,它遵循 sqlcommenter 规范使用注释向 SQL 查询添加元数据。通过使用 sqlcomment 包装现有的 Ent 驱动程序,用户可以利用任何支持该标准的工具来排查查询性能问题。
事不宜迟,让我们看看 sqlcomment 的实际应用。
首先,运行以下命令安装 sqlcomment:
go get ariga.io/sqlcomment
sqlcomment 包装了一个底层的 SQL 驱动程序,因此,我们需要使用 ent 的 sql 模块打开 SQL 连接,而不是使用 Ent 流行的辅助函数 ent.Open。
请确保在以下代码片段中导入 entgo.io/ent/dialect/sql
// 创建数据库驱动程序。
db, err := sql.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
if err != nil {
log.Fatalf("Failed to connect to database: %v", err)
}
// 创建包装 sqlite 驱动程序的 sqlcomment 驱动程序。
drv := sqlcomment.NewDriver(db,
sqlcomment.WithDriverVerTag(),
sqlcomment.WithTags(sqlcomment.Tags{
sqlcomment.KeyApplication: "my-app",
sqlcomment.KeyFramework: "net/http",
}),
)
// 创建并配置 ent 客户端。
client := ent.NewClient(ent.Driver(drv))
现在,每当我们执行查询时,sqlcomment 都会在我们设置的 SQL 查询后附加标签。如果我们运行以下查询:
client.User.
Update().
Where(
user.Or(
user.AgeGT(30),
user.Name("bar"),
),
user.HasFollowers(),
).
SetName("foo").
Save()
Ent 将输出以下带注释的 SQL 查询:
UPDATE `users`
SET `name` = ?
WHERE (
`users`.`age` > ?
OR `users`.`name` = ?
)
AND `users`.`id` IN (
SELECT `user_following`.`follower_id`
FROM `user_following`
)
/*application='my-app',db_driver='ent:v0.9.1',framework='net%2Fhttp'*/
如您所见,Ent 输出了一个 SQL 查询,末尾带有一个注释,包含与该查询关联的所有相关信息。
sqlcomment 支持更多标签,并与 OpenTelemetry 和 OpenCensus 集成。 要查看更多示例和场景,请访问 github 仓库。
总结
在这篇文章中,我展示了使用 SQL 注释向查询添加元数据如何帮助关联源代码和数据库查询。接着,我介绍了 sqlcomment——一个向所有查询添加 SQL 标签的 Ent 驱动程序。最后,我通过安装并使用 Ent 配置 sqlcomment 来实际体验了它的功能。如果您喜欢这个代码和/或想贡献代码——请随时查看 GitHub 上的项目。
有问题吗?需要入门帮助?欢迎加入我们的 Discord 服务器 或 Slack 频道。
- 订阅我们的 新闻通讯
- 在 Twitter 上关注我们
- 加入 Gophers Slack 上的 #ent 频道
- 加入 Ent Discord 服务器