{
    "componentChunkName": "component---src-templates-blog-blog-detail-tsx",
    "path": "/blog/hackathon-guide-adds-a-new-feature-to-tidb",
    "result": {"pageContext":{"blog":{"id":"Blogs_425","title":"Hackathon 实用指南丨快速给 TiDB 新增一个功能","tags":["TiDB Hackathon 2022"],"category":{"name":"社区动态"},"summary":"TiDB Hackathon 2022 即将到来，你有 idea 了吗！不够了解 TiDB，不知道如何开始？本文将通过 step-by-step 的方式，介绍如何快速给 TiDB 新增加一个功能。","body":"TiDB Hackathon 2022 火热报名中！你报名了吗？你有 idea 了吗？\n\n有了 idea，但是不够了解 TiDB，不知道如何动手实践？本文将通过 step-by-step 的方式，介绍如何快速给 TiDB 新增一个功能，让没有太多知识背景的人也能快速上手。\n\nps：参加 TiDB 产品组的小伙伴，想给 TiDB 组件增加新功能的，快来围观！\n\n假设我们想要将 SST 文件导入 TiDB 中，通过新增 `LOAD SST FILE <file_path>` 语法来实现。\n\nTiDB 数据库在收到一条 SQL 请求后，大概的执行流程是 生成 AST 语法树 -> 生成执行计划 -> 构造 Executor 并执行。我们先来实现语法。\n\n## 语法实现\n\n要如何实现语法呢？我们可以照葫芦画瓢，找一个类似的 `LOAD DATA` 语法作为葫芦，然后开始画瓢。\n\n### Step-1: 新增 AST 语法树\n\n`LOAD DATA` 语法是用 `ast.LoadDataStmt` 表示的，我们照葫芦画瓢在 `tidb/parser/ast/dml.go` 中新增一个 `LoadSSTFileStmt AST` 语法树：\n\n```\n// LoadSSTFileStmt is a statement to load sst file.\ntype LoadSSTFileStmt struct {\n   dmlNode\n\n   Path string\n}\n\n// Restore implements Node interface.\nfunc (n *LoadSSTFileStmt) Restore(ctx *format.RestoreCtx) error {\n   ctx.WriteKeyWord(\"LOAD SST FILE \")\n   ctx.WriteString(n.Path)\n   return nil\n}\n\n// Accept implements Node Accept interface.\nfunc (n *LoadSSTFileStmt) Accept(v Visitor) (Node, bool) {\n   newNode, _ := v.Enter(n)\n   return v.Leave(newNode)\n}\n```\n\nRestore 方法用来根据 AST 语法树还原出对应的 SQL 语句。 Accept 方法是方便其他工具遍历这个 AST 语法树，例如 TiDB 在预处理是会通过 AST 语法树的 Accept 方法来遍历 AST 语法树中的所有节点。\n\n### Step-2：新增语法\n\nLOAD DATA 语法是通过 `LoadDataStmt` 实现的，我们也照葫芦画瓢，在 `tidb/parser/parser.y` 中，新增 `LoadSSTFileStmt` 语法，这里需要修改好几处地方，下面用 git diff 展示修改：\n\n```\ndiff --git a/parser/parser.y b/parser/parser.y\nindex 1539bb13db..079859e8a9 100644\n--- a/parser/parser.y\n+++ b/parser/parser.y\n@@ -243,6 +243,7 @@ import (\n        sqlCalcFoundRows  \"SQL_CALC_FOUND_ROWS\"\n        sqlSmallResult    \"SQL_SMALL_RESULT\"\n        ssl               \"SSL\"\n+       sst               \"SST\"\n        starting          \"STARTING\"\n        statsExtended     \"STATS_EXTENDED\"\n        straightJoin      \"STRAIGHT_JOIN\"\n@@ -908,6 +909,7 @@ import (\n        IndexAdviseStmt            \"INDEX ADVISE statement\"\n        KillStmt                   \"Kill statement\"\n        LoadDataStmt               \"Load data statement\"\n+       LoadSSTFileStmt            \"Load sst file statement\"\n        LoadStatsStmt              \"Load statistic statement\"\n        LockTablesStmt             \"Lock tables statement\"\n        NonTransactionalDeleteStmt \"Non-transactional delete statement\"\n@@ -11324,6 +11326,7 @@ Statement:\n |      IndexAdviseStmt\n |      KillStmt\n |      LoadDataStmt\n+|      LoadSSTFileStmt\n |      LoadStatsStmt\n |      PlanReplayerStmt\n |      PreparedStmt\n@@ -13496,6 +13499,14 @@ LoadDataStmt:\n                $ = x\n        }\n\n+LoadSSTFileStmt:\n+       \"LOAD\" \"SST\" \"FILE\" stringLit\n+       {\n+               $ = &ast.LoadSSTFileStmt{\n+                       Path: $4,\n+               }\n+       }\n+\n```\n\n上面的修改中：\n\n第 9 行是因为语法中 `SST` 是一个新的关键字，所以需要注册一个新的关键字。\n\n第 17 行 和 25 行是注册一个新语法叫 `LoadSSTFileStmt` 。\n\n第 33 - 40 行是定义 `LoadSSTFileStmt` 语法结构为：`LOAD SST FILE <file_path>` ，这里前 3 个关键字都是固定的，所以直接定义  `\"LOAD\" \"SST\" \"FILE\"`即可，第 4 个是文件路径，一个变量值，我们用 `stringLit` 来提取这个变量的值，然后再用这个的值来初始化 `ast.LoadSSTFileStmt`，其中 $4 是指第 4 个变量 `stringLit` 的值。\n\n因为引入了新的关键字 `SST` ，所以还需要在 `tidb/parser/misc.go` 中新增这个关键字：\n\n```\ndiff --git a/parser/misc.go b/parser/misc.go\nindex 140619bb07..418e9dd6a4 100644\n--- a/parser/misc.go\n+++ b/parser/misc.go\n@@ -669,6 +669,7 @@ var tokenMap = map[string]int{\n        \"SQL_TSI_YEAR\":             sqlTsiYear,\n        \"SQL\":                      sql,\n        \"SSL\":                      ssl,\n+       \"SST\":                      sst,\n        \"STALENESS\":                staleness,\n        \"START\":                    start,\n        \"STARTING\":                 starting,\n```\n\n### Step-3：编译和测试\n\n编译生成新的 `parser` 文件。\n\n```\ncd parser\nmake fmt  #格式化代码\nmake      # 编译生成新的 parser 文件\n```\n\n我们可以在 `tidb/parser/parser_test.go` 文件中的 `TestDMLStmt` 中新增一个测试，来验证我们新增的语法生效了，下面是 git diff 展示的修改：\n\n```\ndiff --git a/parser/parser_test.go b/parser/parser_test.go\nindex 7093c3889f..d2c75c4c59 100644\n--- a/parser/parser_test.go\n+++ b/parser/parser_test.go\n@@ -666,6 +666,9 @@ func TestDMLStmt(t *testing.T) {\n                {\"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE t1 FIELDS TERMINATED BY ',' LINES TERMINATED BY '\\n';\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' IGNORE INTO TABLE `t1` FIELDS TERMINATED BY ','\"},\n                {\"LOAD DATA LOCAL INFILE '/tmp/t.csv' REPLACE INTO TABLE t1 FIELDS TERMINATED BY ',' LINES TERMINATED BY '\\n';\", true, \"LOAD DATA LOCAL INFILE '/tmp/t.csv' REPLACE INTO TABLE `t1` FIELDS TERMINATED BY ','\"},\n\n+               // load sst file test\n+               {\"load sst file 'table0.sst'\", true, \"LOAD SST FILE 'table0.sst'\"},\n+\n```\n\n然后跑测试：\n\n```\ncd parser\nmake test #跑 parser 的所有测试，快速验证可以用 go test -run=\"TestDMLStmt\" 命令只跑修改的 TestDMLStmt 测试\n```\n\n## 生成执行计划\n\nTiDB 在生成 AST 语法树后，需要生成对应的执行计划。我们需要先定义 `LOAD SST FILE` 的执行计划。同样的照葫芦画瓢，我们先在 `tidb/planner/core/common_plans.go` 文件中找到 `LOAD DATA` 的执行计划 `LoadData`, 然后开始画瓢定义 `LoadSSTFile` 执行计划：\n\n```\n// LoadSSTFile represents a load sst file plan.\ntype LoadSSTFile struct {\n        baseSchemaProducer\n\n        Path        string\n}\n```\n\n为了让 TiDB 能更具 `ast.LoadSSTFileStmt` 语法树生成对应的 `LoadSSTFile` 执行计划，\n\n需要在 `tidb/planner/core/planbuilder.go` 文件中，参考 `buildLoadData` 方法，来实现我们的 `buildLoadSSTFile` 方法，用来生成执行计划, 下面是 git diff 展示修改内容：\n\n```\ndiff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go\nindex ad7ce64748..c68e992b35 100644\n--- a/planner/core/planbuilder.go\n+++ b/planner/core/planbuilder.go\n@@ -734,6 +734,8 @@ func (b *PlanBuilder) Build(ctx context.Context, node ast.Node) (Plan, error) {\n                return b.buildInsert(ctx, x)\n        case *ast.LoadDataStmt:\n                return b.buildLoadData(ctx, x)\n+       case *ast.LoadSSTFileStmt:\n+               return b.buildLoadSSTFile(x)\n@@ -3979,6 +3981,13 @@ func (b *PlanBuilder) buildLoadData(ctx context.Context, ld *ast.LoadDataStmt) (\n        return p, nil\n }\n\n+func (b *PlanBuilder) buildLoadSSTFile(ld *ast.LoadSSTFileStmt) (Plan, error) {\n+       p := &LoadSSTFile{\n+               Path: ld.Path,\n+       }\n+       return p, nil\n+}\n+\n```\n\n## 构造 Executor 并执行\n\n生成执行计划之后，就需要构造对应的 Executor 然后执行了。TiDB 是用 Volcano 执行引擎，你可以将相关的初始化工作放在 `Open` 方法中，将主要功能的实现都放在 `Next` 方法中，以及执行完成后，在 `Close` 方法中执行相关的清理和释放资源的操作。\n\n我们需要先定义 `LOAD SST FILE` 的 Executor，并让其实现 `executor.Executor` 接口，可以把相关定义放到 `tidb/executor/executor.go` 文件中：\n\n```\n// LoadSSTFileExec represents a load sst file executor.\ntype LoadSSTFileExec struct {\n   baseExecutor\n\n   path string\n   done bool\n}\n\n// Open implements the Executor Open interface.\nfunc (e *LoadSSTFileExec) Open(ctx context.Context) error {\n   logutil.BgLogger().Warn(\"----- load sst file open, you can initialize some resource here\")\n   return nil\n}\n\n// Next implements the Executor Next interface.\nfunc (e *LoadSSTFileExec) Next(ctx context.Context, req *chunk.Chunk) error {\n   req.Reset()\n   if e.done {\n      return nil\n   }\n   e.done = true\n\n   logutil.BgLogger().Warn(\"----- load sst file exec\", zap.String(\"file\", e.path))\n   return nil\n}\n\n// Close implements the Executor Close interface.\nfunc (e *LoadSSTFileExec) Close() error {\n   logutil.BgLogger().Warn(\"----- load sst file close, you can release some resource here\")\n   return nil\n}\n```\n\n如果没有初始化工作和清理工作，你也可以不用实现 `Open` 和 `Close` 方法，因为 `baseExecutor` 已经实现过了。\n\n这里为了简化教程在 `LoadSSTFileExec Executor` 中仅仅是输出了几条 Log，你需要将自己功能具体实现的代码放在这里。\n\n然后为了让 TiDB 能够根据 `LoadSSTFile` 执行计划来生成 `LoadSSTFileExec Executor`, 需要修改 `tidb/executor/builder.go` 文件，下面是用 git diff 展示的修改：\n\n```\ndiff --git a/executor/builder.go b/executor/builder.go\nindex 1154633bd5..4f0478daa6 100644\n--- a/executor/builder.go\n+++ b/executor/builder.go\n@@ -199,6 +199,8 @@ func (b *executorBuilder) build(p plannercore.Plan) Executor {\n                return b.buildInsert(v)\n        case *plannercore.LoadData:\n                return b.buildLoadData(v)\n+       case *plannercore.LoadSSTFile:\n+               return b.buildLoadSSTFile(v)\n        case *plannercore.LoadStats:\n                return b.buildLoadStats(v)\n        case *plannercore.IndexAdvise:\n@@ -944,6 +946,14 @@ func (b *executorBuilder) buildLoadData(v *plannercore.LoadData) Executor {\n        return loadDataExec\n }\n\n+func (b *executorBuilder) buildLoadSSTFile(v *plannercore.LoadSSTFile) Executor {\n+       e := &LoadSSTFileExec{\n+               baseExecutor: newBaseExecutor(b.ctx, nil, v.ID()),\n+               path:         v.Path,\n+       }\n+       return e\n+}\n+\n```\n\n## 验证\n\n到此，我们已经成功的在 TiDB 中新增了一个 “功能”， 我们可以编译 TiDB 并启动后验证下：\n\n```\nmake    #编译 TiDB server\nbin/tidb-server  # 启动一个 TiDB server\n```\n\n然后新起一个终端，用 mysql 客户端连上去试试新功能：\n\n```\n▶ mysql -u root -h 127.0.0.1 -P 4000\n\nmysql> load sst file 'table0.sst';\nQuery OK, 0 rows affected (0.00 sec)\n```\n\n可以看到执行成功了，并且在 tidb-server 的输出日志中，可以看到我们这个功能的 Executor 执行时的日志输出：\n\n```\n[2022/09/19 15:24:02.745 +08:00] [WARN] [executor.go:2213] [\"----- load sst file open, you can initialize some resource here\"]\n[2022/09/19 15:24:02.745 +08:00] [WARN] [executor.go:2225] [\"----- load sst file exec\"] [file=table0.sst]\n[2022/09/19 15:24:02.745 +08:00] [WARN] [executor.go:2231] [\"----- load sst file close, you can release some resource here\"]\n```\n\n## 总结\n\n本文的代码示例：https://github.com/pingcap/tidb/pull/37936/files\n\n本文通过“照葫芦画瓢” 的方式，教你如何在 TiDB 中新增一个功能，但也忽略了一些细节，例如权限检查，添加完备的测试等等，希望能对读者有所帮助。如果想要了解更多的知识背景和细节，推荐阅读 [TiDB Development Guide](https://pingcap.github.io/tidb-dev-guide/) 和 [TiDB 源码阅读](/blog/?tag=TiDB%20源码阅读)博客。","date":"2022-10-09","author":"陈霜","fillInMethod":"writeDirectly","customUrl":"hackathon-guide-adds-a-new-feature-to-tidb","file":null,"relatedBlogs":[{"relatedBlog":{"body":"![hackathon 2022 kv.jpeg](https://img1.www.pingcap.com/prod/hackathon_2022_kv_000f450a54.jpeg)\n\n一年一度的 TiDB Hackathon 又来啦！\n\n[TiDB Hackathon 2022](https://tidb.net/events/hackathon2022) 主题为「**Possibility at Scale**」，9 月 13 日正式开启，线下决赛将在 2022 年 10 月 22 - 23 日举行。期待与你一起打破传统技术边界，突破固有思维局限，用 TiDB 释放创新的更多可能性。\n\n本届 TiDB Hackathon 将面向更广泛人群，分为**应用组**与 **TiDB 产品组**两大赛道。无论你是应用开发者、数据库开发者、数据库上下游生态从业人员，还是数据库使用者，都可以找到适合自己的方向，一起“玩转” TiDB。\n\nTiDB Hackathon 报名通道于 2022 年 9 月 13 日正式开启，**选手们可以自行组队参赛，通过初赛甄选后，将在现场完成 Coding 及决赛答辩，优胜队伍将获得奖金、技术和资源商的支持**。大赛评委阵容豪华，数据库领域资深专家、社区技术大牛、顶级投资人代表将对项目进行深度点评。此外，还有顶级投资人全程参与评选，让你的实力被更多人看到。\n\n**扫描下图二维码，立即报名参赛**，或前往 [TiDB Hackathon 2022](https://tidb.net/events/hackathon2022) 活动页报名。\n\n![报名参赛.jpeg](https://img1.www.pingcap.com/prod/_f7bfacf978.jpeg)\n\n从 2017 年到 2022 年，TiDB Hackathon 不断升级，吸引了全球 1000 + 技术爱好者参与，先后诞生了诸如 UDF 引擎、TiExec、TiMatch 等深受好评的硬核项目，也有 zh.md、TiDB 驾驶舱、pCloud 等新颖有趣的项目。同时，部分优秀项目还在海内外媒体平台获得了多重曝光，借助 TiDB 社区力量为项目提供更多生命力。\n\n在 TiDB Hackathon ，你可以尽情发挥想象力与创造力，全情投入，实现自己的 idea。我们希望你可以永葆对技术的热情与好奇心，在代码的世界中勇敢探索、一往无前。我们在 TiDB Hackathon 2022 等你，期待与你共赴这场技术盛宴！\n\n## 赛事亮点\n\n🌟 **奖金丰厚**\n\n大赛总奖金池高达 35 万元，奖项多达 10+ 个，涵盖各个方向，力求全方位挖掘各参赛项目的价值。\n\n🌟 **各路大神同台竞技**\n\n技术大神齐聚一堂，上演“神仙打架”，场面超燃。高手之间的巅峰对决，精彩纷呈，让人大开眼界。\n\n🌟 **高质量交流**\n\n数据领域知名专家、社区技术大牛担任大赛评委，对项目进行深入点评，还有顶级投资人全程参与评选，你将不止收获硬核的技术反馈，还会获得前瞻性启发。\n\n🌟 **优秀项目专题采访**\n\n大赛结束后，我们将对优秀项目进行专题采访，在海内外技术圈多重曝光，提升优秀项目的知名度，借助 TiDB 社区力量为项目提供更多生命力。\n\n## 丰厚奖金\n\n**奖金池 35 万元，10+ 奖项，20+ 获奖团队**\n\n![丰厚奖金.jpeg](https://img1.www.pingcap.com/prod/_d265519d19.jpeg)\n\n**神秘定制社区周边**\n\n![定制社区周边.jpeg](https://img1.www.pingcap.com/prod/_c6c05c4a61.jpeg)\n\n## 参赛对象\n\n不管你是数据库内核工程师、数据库生态上下游开发者，还是应用开发者，只要你有 idea，都可以报名参赛，一展你的风采！\n\n## 赛道设置\n\n**应用组**\n\n以体现 TiDB 产品价值为主，基于 TiDB 之上实现代码开源的产品、工具、应用等均可。部署方式上，更推荐基于 Cloud 构建 TiDB 相关应用。推荐领域：游戏、电商、金融科技、公益等。\n\n**TiDB 产品组**\n\n为 TiDB 内核产品以及 TiCDC、TiDB Lightning、TiUP 等周边工具的性能、稳定性、易用性或功能等各方面做出提升。\n\n## 赛程安排\n\n- 报名：即日起 - 10 月 17 日，开启报名\n\n- 组队：9 月 17 日，参加「非正式会谈 — 创意脑暴会」，获取项目灵感（详见下方介绍）\n\n- 线上初赛：报名后 -  10 月 17 日，提交 RFC 进入初赛环节\n\n- 名单公布：10 月 19 日，查看决赛入围名单\n\n- 现场 Coding & 决赛：10 月 22 日 - 10 月 23 日，现场 Coding & 决赛答辩\n\n![比赛日程.png](https://img1.www.pingcap.com/prod/_357da0cc3c.png)\n\n## 评委阵容\n\n数据库领域知名专家、社区技术大牛、顶级投资人代表等担当评委，还有顶级投资人全程坐镇，对比赛项目深入点评。\n\n![评委.png](https://img1.www.pingcap.com/prod/_db0a886a7b.png)\n\n<center>（评委按姓名首字母排序）</center>\n\n比赛有输赢，技术无高低。即便最终未能问鼎巅峰，朝着心之所向全力冲刺依旧是一段值得回忆的旅程。秉承不断突破和创造的黑客精神，来一场技术的狂欢盛宴吧。放码过来！\n\n## 创意脑暴会给你灵感\n\n**TiDB Hackathon 2022 非正式会谈 —— 创意脑暴会**来啦，这里有超多 idea，特邀东旭以及资深架构师们在线脑暴，给你超丰富项目灵感。9月17日 本周六 10:30-12:00（GTM+8），线上见～\n\n![创意脑暴.jpeg](https://img1.www.pingcap.com/prod/_a800efa48b.jpeg)\n\n## 合作伙伴\n\n![合作伙伴.png](https://img1.www.pingcap.com/prod/_c6b365d0d3.png)\n\n了解 [TiDB Hackathon 2022](https://tidb.net/events/hackathon2022) 更多精彩！\n\n","author":"PingCAP","category":3,"customUrl":"tidb-hackathon-2022-is-coming","fillInMethod":"writeDirectly","id":426,"summary":"一年一度的 TiDB Hackathon 又来啦！TiDB Hackathon 2022 主题为「Possibility at Scale」,9 月 13 日正式开启，线下决赛将在 2022 年 10 月 22 日 23 日举行。","tags":["TiDB Hackathon 2022"],"title":"TiDB Hackathon 2022丨总奖金池超 35 万！邀你唤醒代码世界的更多可能性！"}},{"relatedBlog":{"body":"![banner.jpeg](https://img1.www.pingcap.com/prod/banner_6e96e050b4.jpeg)\n\n一年一度黑客们的狂欢——[TiDB Hackathon 2022](https://tidb.net/events/hackathon2022) 报名已开启，万元奖金等你来拿，还有技术专家、顶级投资人全程坐镇，你的实力将被更多人看到。\n\nTiBD Hackathon 2022 ·「Possibility at Scale」，邀请你一起打破传统技术边界，突破固有思维局限，用 TiDB 释放创新的更多可能性。\n\n悄悄说：今年真的不卷，值得一试！\n\n两大赛道，任选：\n\n- 应用组：推荐噢，因为特别奖项更多！\n\n以体现 TiDB 产品价值为主，使用 TiDB 构建代码开源的产品、工具、应用等均可。部署方式上，更推荐基于 Cloud 构建 TiDB 相关应用。常见应用领域：游戏、电商、金融科技、公益等。\n\n- TiDB 产品组：延续传统，保持初心\n\n为 TiDB 内核产品以及 TiCDC、TiDB Lightning、TiUP 等周边工具的性能、稳定性、易用性或功能等各方面做出提升。\n\n扫描下方二维码立即报名参与！\n\n![报名.jpeg](https://img1.www.pingcap.com/prod/_3b43724e2f.jpeg)\n\n听说你想参加 TiDB Hackathon，却没有 idea？\n\n别担心，脑洞达人东旭和他的架构师朋友们在创意脑暴会上分享的项目 idea 都整理好啦，快来看看有没有你感兴趣的~（ps：搭配视频查看 idea 详细介绍，效果更佳哦~） \n\n**创意贡献嘉宾**\n\n黄东旭 PingCAP 联合创始人兼 CTO\n\n姚维 PingCAP 全球社区生态负责人\n\n张兴晔 多点系统架构师\n\nCheng Chen PingCAP Product Manager\n\n[脑暴会视频](https://www.bilibili.com/video/BV1yG411u7N9/)\n\n## 应用组\n\n![应用组.jpeg](https://img1.www.pingcap.com/prod/_e769b14808.jpeg)\n\n今年应用组的决赛参赛项目仅要求是 demo 级别的，例如以下项目示例：\n\n- OSS Insight：https://ossinsight.io/\n\n这是一个基于 TiDB 实现的，数十亿 GitHub events 数据构建的洞察工具。只要你会写 SQL，就可以基于 Docusaurus、Apache ECharts 构建一个强大、酷炫的数据洞察工具。\n\n- TiDB & Snowflake Demo：https://tidb-snowflake-e-commerce-demo.vercel.app/\n\n这是一个基于 TiDB 和 Snowflake 构建的电子商务系统，该系统使用了 TiDB 强大的实时 HTAP 能力和 Snowflake 的离线分析能力，来处理系统中大量的数据。\n\n- Ti-Click：http://ide.ti-click.com/\n\n这是 TiDB Hackathon 2021 的 20 强项目之一，项目通过在线 IDE 的方式，快速搭建基于 TiDB 的 Example App 的开发和在线编译的实验室，可帮助开发者快速学习 TiDB。\n\n- Bookshop\n\n这是一个基于 TiDB 搭建的在线书店应用，你可以通过它来学习如何导入表结构和数据，以及如何基于这些数据来编写 SQL。\n\n[这篇文章](https://docs.pingcap.com/zh/tidb/stable/dev-guide-bookshop-schema-design)也以 Bookshop 应用的数据表结构和数据为基础来编写示例 SQL，为你介绍如何导入该应用的表结构和数据，以及其数据表结构的定义。\n\n- Gitpod\n\n对于 TiDB 初学者，我们基于 Gitpod，提供了一个云原生开发环境的使用帮助，你可以直接从你的浏览器或桌面 IDE 启动一个远程的 TiDB 开发环境，快速体验 TiDB 的能力。我们编写了全新的 TiDB 开发者文档，这份文档可以帮助应用开发者，在最短时间内上手 TiDB。\n\nTiDB 开发者文档：https://docs.pingcap.com/zh/tidb/stable/dev-guide-overview\n\n## TiDB 产品组\n\n![TiDB 产品组.jpeg](https://img1.www.pingcap.com/prod/Ti_DB_77ad779a1c.jpeg)\n\n## 彩蛋组\n\n彩蛋组不可更改 TiDB/TiKV 源码，仅可使用插件方式进行 Hack。\n\n![彩蛋组.jpeg](https://img1.www.pingcap.com/prod/_f6b386df89.jpeg)\n\n希望可以给你一些方向与灵感！更多项目 idea 也可以来 [Hackathon 2022 创意库](https://asktug.com/t/topic/933124)找灵感。\n\n看到这么多 idea，你是否跃跃欲试了呢？\n\n热爱编程，勇于探索，就能参赛\n\n你离万元大奖只有一个报名的距离~\n\n了解 [TiDB Hackathon 2022 ](https://tidb.net/events/hackathon2022)更多详情！","author":"PingCAP","category":3,"customUrl":"hackathon-idea-list-for-reference","fillInMethod":"writeDirectly","id":427,"summary":"一年一度黑客们的狂欢——TiDB Hackathon 2022 报名已开启，万元奖金等你来拿，还有技术专家、顶级投资人全程坐镇，你的实力将被更多人看到。","tags":["TiDB Hackathon 2022"],"title":"Hackathon idea 清单出炉，总有一款适合你"}}]}}},
    "staticQueryHashes": ["1327623483","1820662718","3081853212","3430003955","3649515864","4265596160","63159454"]}