diff --git a/README.md b/README.md index 3b37c10..88806d5 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Gorm Sharding plugin using SQL parser and replace for splits large tables into s Gorm Sharding 是一个业务污染小,高性能的数据库分表方案。通过 SQL 解析和替换,实现分表逻辑,让查询正确的根据规则执行到分表里面。 -[![](https://mermaid.ink/img/eyJjb2RlIjoiZ3JhcGggVERcbmZpcnN0KFwiU1FMIFF1ZXJ5PGJyPjxicj5cbnNlbGVjdCAqIGZyb20gb3JkZXJzPGJyPlxud2hlcmUgdXNlcl9pZCA9ID8gYW5kIHN0YXR1cyA9ID88YnI-XG5saW1pdCAxMCBvcmRlciBieSBpZCBkZXNjPGJyPlxuYXJncyA9IFsxMDAsIDFdXCIpXG5cbmZpcnN0LS0tPnwgR29ybSBRdWVyeSB8ZGJbXCJHb3JtIERCXCJdXG5cbnN1YmdyYXBoIFwiR29ybVwiXG4gIGRiLS0-Z29ybV9xdWVyeVxuICBnb3JtX3F1ZXJ5W1wiY29ublBvb2wuUXVlcnlDb250ZXh0KHNxbCwgYXJncyk8YnI-XCJdXG5lbmRcblxuc3ViZ3JhcGggXCJkYXRhYmFzZS9zcWwgLSBDb25uXCJcbiAgRXhlY0NvbnRleHRbL1wiRXhlY0NvbnRleHRcIi9dXG4gIFF1ZXJ5Q29udGV4dFsvXCJRdWVyeUNvbnRleHRcIi9dXG4gIFF1ZXJ5Um93Q29udGV4dFsvXCJRdWVyeVJvd0NvbnRleHRcIi9dXG4gIGdvcm1fcXVlcnktLT5Db25uXG4gIENvbm4oW1wiQ29ublwiXSlcbiAgQ29ubi0tPkV4ZWNDb250ZXh0XG4gIENvbm4tLT5RdWVyeUNvbnRleHRcbiAgQ29ubi0tPlF1ZXJ5Um93Q29udGV4dFxuZW5kXG5cbnN1YmdyYXBoIHNoYXJkaW5nIFtcIk15Q29ublBvb2xcIl1cbiAgUXVlcnlDb250ZXh0LS0-cm91dGVyLS0-Zm9ybWF0X3NxbC0tPnBhcnNlLS0-Y2hlY2tfdGFibGVcbiAgcm91dGVyW1tcInJvdXRlcihzcWwsIGFyZ3MpPGJyPjxicj5cIl1dXG4gIGZvcm1hdF9zcWw-XCJGb3JtYXQgc3FsLCBhcmdzIGZvciBnZXQgZnVsbCBTUUw8YnI-PGJyPlxuICAgIHNxbCA9IHNlbGVjdCAqIGZyb20gb3JkZXJzPGJyPlxuICAgIHdoZXJlIHVzZXJfaWQgPSAxMDAgYW5kIHN0YXR1cyA9IDE8YnI-XG4gICAgbGltaXQgMTAgb3JkZXIgYnkgaWQgZGVzY1wiXVxuXG4gIGNoZWNrX3RhYmxle1wiQ2hlY2sgc2hhcmRpbmcgcnVsZXM8YnI-YnkgdGFibGUgbmFtZVwifVxuICBjaGVja190YWJsZS0tPnwgRXhpc3QgfHByb2Nlc3NfYXN0XG4gIGNoZWNrX3RhYmxlXzF7e1wiUmV0dXJuIFJhdyBTUUxcIn19XG4gIG5vdF9tYXRjaF9lcnJvclsvXCJSZXR1cm4gRXJyb3I8YnI-U1FMIHF1ZXJ5IG11c3QgaGFzIHNoYXJkaW5nIGtleVwiXFxdXG5cbiAgcGFyc2VbW1wiUGFyc2VyIFNRTCB0byBnZXQgQVNUPGJyPlxuICA8YnI-XG4gIGFzdCA9IHNxbHBhcnNlci5QYXJzZShzcWwpXCJdXVxuXG4gIGNoZWNrX3RhYmxlLS4tPnwgTm90IGV4aXN0IHxjaGVja190YWJsZV8xXG4gIHByb2Nlc3NfYXN0KChcIlNoYXJkaW5nIHJ1bGVzXCIpKVxuICBnZXRfbmV3X3RhYmxlX25hbWVbW1wiVXNlIHZhbHVlIGluIFdoZXJlVmFsdWUgKDEwMCkgZm9yIGdldCBzaGFyZGluZyB0YWJsZSBpbmRleDxicj5vcmRlcnMgKyAoMTAwICUgMTYpPGJyPlNoYXJkaW5nIFRhYmxlID0gb3JkZXJzXzRcIl1dXG4gIG5ld19zcWx7e1wic2VsZWN0ICogZnJvbSBvcmRlcnNfNDxicj53aGVyZSB1c2VyX2lkID0gMTAwIGFuZCBzdGF0dXMgPSAxPGJyPmxpbWl0IDEwIG9yZGVyIGJ5IGlkIGRlc2NcIn19XG5cbiAgcHJvY2Vzc19hc3QtLi0-fCBOb3QgbWF0Y2ggU2hhcmRpbmdLZXkgfG5vdF9tYXRjaF9lcnJvclxuICBwcm9jZXNzX2FzdC0tPnwgTWF0Y2ggU2hhcmRpbmdLZXkgfG1hdGNoX3NoYXJkaW5nX2tleS0tPnwgR2V0IHRhYmxlIG5hbWUgfGdldF9uZXdfdGFibGVfbmFtZS0tPnwgUmVwbGFjZSBUYWJsZU5hbWUgdG8gZ2V0IG5ldyBTUUwgfG5ld19zcWxcbmVuZFxuXG5cbnN1YmdyYXBoIGRhdGFiYXNlIFtEYXRhYmFzZV1cbiAgcG9zdHNfb3RoZXJbKFwib3JkZXJzXzAsIG9yZGVyc18xIC4uLiBvcmRlcnNfM1wiKV1cbiAgcG9zdHNfNFsob3JkZXJzXzQpXVxuICBwb3N0c19sYXN0WyhcIm9yZGVyc181IC4uLiBvcmRlcnNfMTVcIildXG4gIG90aGVyX3RhYmxlc1soT3RoZXIgbm9uLXNoYXJkaW5nIHRhYmxlczxicj51c2Vycywgc3RvY2tzLCB0b3BpY3MgLi4uKV1cblxuICBuZXdfc3FsLS0-fCBTaGFyZGluZyBRdWVyeSB8IG9yZGVyc180XG4gIGNoZWNrX3RhYmxlXzEtLi0-fCBOb25lIHNoYXJkaW5nIFF1ZXJ5IHxvdGhlcl90YWJsZXNcbmVuZFxuXG5wb3N0c180LS0-cmVzdWx0XG5vdGhlcl90YWJsZXMtLi0-cmVzdWx0XG5yZXN1bHRbL1F1ZXJ5IHJlc3VsdHNcXF0iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9LCJ1cGRhdGVFZGl0b3IiOmZhbHNlLCJhdXRvU3luYyI6dHJ1ZSwidXBkYXRlRGlhZ3JhbSI6ZmFsc2V9)](https://mermaid.live/edit#eyJjb2RlIjoiZ3JhcGggVERcbmZpcnN0KFwiU1FMIFF1ZXJ5PGJyPjxicj5cbnNlbGVjdCAqIGZyb20gb3JkZXJzPGJyPlxud2hlcmUgdXNlcl9pZCA9ID8gYW5kIHN0YXR1cyA9ID88YnI-XG5saW1pdCAxMCBvcmRlciBieSBpZCBkZXNjPGJyPlxuYXJncyA9IFsxMDAsIDFdXCIpXG5cbmZpcnN0LS0tPnwgR29ybSBRdWVyeSB8ZGJbXCJHb3JtIERCXCJdXG5cbnN1YmdyYXBoIFwiR29ybVwiXG4gIGRiLS0-Z29ybV9xdWVyeVxuICBnb3JtX3F1ZXJ5W1wiY29ublBvb2wuUXVlcnlDb250ZXh0KHNxbCwgYXJncyk8YnI-XCJdXG5lbmRcblxuc3ViZ3JhcGggXCJkYXRhYmFzZS9zcWwgLSBDb25uXCJcbiAgRXhlY0NvbnRleHRbL1wiRXhlY0NvbnRleHRcIi9dXG4gIFF1ZXJ5Q29udGV4dFsvXCJRdWVyeUNvbnRleHRcIi9dXG4gIFF1ZXJ5Um93Q29udGV4dFsvXCJRdWVyeVJvd0NvbnRleHRcIi9dXG4gIGdvcm1fcXVlcnktLT5Db25uXG4gIENvbm4oW1wiQ29ublwiXSlcbiAgQ29ubi0tPkV4ZWNDb250ZXh0XG4gIENvbm4tLT5RdWVyeUNvbnRleHRcbiAgQ29ubi0tPlF1ZXJ5Um93Q29udGV4dFxuZW5kXG5cbnN1YmdyYXBoIHNoYXJkaW5nIFtcIk15Q29ublBvb2xcIl1cbiAgUXVlcnlDb250ZXh0LS0-cm91dGVyLS0-Zm9ybWF0X3NxbC0tPnBhcnNlLS0-Y2hlY2tfdGFibGVcbiAgcm91dGVyW1tcInJvdXRlcihzcWwsIGFyZ3MpPGJyPjxicj5cIl1dXG4gIGZvcm1hdF9zcWw-XCJGb3JtYXQgc3FsLCBhcmdzIGZvciBnZXQgZnVsbCBTUUw8YnI-PGJyPlxuICAgIHNxbCA9IHNlbGVjdCAqIGZyb20gb3JkZXJzPGJyPlxuICAgIHdoZXJlIHVzZXJfaWQgPSAxMDAgYW5kIHN0YXR1cyA9IDE8YnI-XG4gICAgbGltaXQgMTAgb3JkZXIgYnkgaWQgZGVzY1wiXVxuXG4gIGNoZWNrX3RhYmxle1wiQ2hlY2sgc2hhcmRpbmcgcnVsZXM8YnI-YnkgdGFibGUgbmFtZVwifVxuICBjaGVja190YWJsZS0tPnwgRXhpc3QgfHByb2Nlc3NfYXN0XG4gIGNoZWNrX3RhYmxlXzF7e1wiUmV0dXJuIFJhdyBTUUxcIn19XG4gIG5vdF9tYXRjaF9lcnJvclsvXCJSZXR1cm4gRXJyb3I8YnI-U1FMIHF1ZXJ5IG11c3QgaGFzIHNoYXJkaW5nIGtleVwiXFxdXG5cbiAgcGFyc2VbW1wiUGFyc2VyIFNRTCB0byBnZXQgQVNUPGJyPlxuICA8YnI-XG4gIGFzdCA9IHNxbHBhcnNlci5QYXJzZShzcWwpXCJdXVxuXG4gIGNoZWNrX3RhYmxlLS4tPnwgTm90IGV4aXN0IHxjaGVja190YWJsZV8xXG4gIHByb2Nlc3NfYXN0KChcIlNoYXJkaW5nIHJ1bGVzXCIpKVxuICBnZXRfbmV3X3RhYmxlX25hbWVbW1wiVXNlIHZhbHVlIGluIFdoZXJlVmFsdWUgKDEwMCkgZm9yIGdldCBzaGFyZGluZyB0YWJsZSBpbmRleDxicj5vcmRlcnMgKyAoMTAwICUgMTYpPGJyPlNoYXJkaW5nIFRhYmxlID0gb3JkZXJzXzRcIl1dXG4gIG5ld19zcWx7e1wic2VsZWN0ICogZnJvbSBvcmRlcnNfNDxicj53aGVyZSB1c2VyX2lkID0gMTAwIGFuZCBzdGF0dXMgPSAxPGJyPmxpbWl0IDEwIG9yZGVyIGJ5IGlkIGRlc2NcIn19XG5cbiAgcHJvY2Vzc19hc3QtLi0-fCBOb3QgbWF0Y2ggU2hhcmRpbmdLZXkgfG5vdF9tYXRjaF9lcnJvclxuICBwcm9jZXNzX2FzdC0tPnwgTWF0Y2ggU2hhcmRpbmdLZXkgfG1hdGNoX3NoYXJkaW5nX2tleS0tPnwgR2V0IHRhYmxlIG5hbWUgfGdldF9uZXdfdGFibGVfbmFtZS0tPnwgUmVwbGFjZSBUYWJsZU5hbWUgdG8gZ2V0IG5ldyBTUUwgfG5ld19zcWxcbmVuZFxuXG5cbnN1YmdyYXBoIGRhdGFiYXNlIFtEYXRhYmFzZV1cbiAgcG9zdHNfb3RoZXJbKFwib3JkZXJzXzAsIG9yZGVyc18xIC4uLiBvcmRlcnNfM1wiKV1cbiAgcG9zdHNfNFsob3JkZXJzXzQpXVxuICBwb3N0c19sYXN0WyhcIm9yZGVyc181IC4uLiBvcmRlcnNfMTVcIildXG4gIG90aGVyX3RhYmxlc1soT3RoZXIgbm9uLXNoYXJkaW5nIHRhYmxlczxicj51c2Vycywgc3RvY2tzLCB0b3BpY3MgLi4uKV1cblxuICBuZXdfc3FsLS0-fCBTaGFyZGluZyBRdWVyeSB8IG9yZGVyc180XG4gIGNoZWNrX3RhYmxlXzEtLi0-fCBOb25lIHNoYXJkaW5nIFF1ZXJ5IHxvdGhlcl90YWJsZXNcbmVuZFxuXG5wb3N0c180LS0-cmVzdWx0XG5vdGhlcl90YWJsZXMtLi0-cmVzdWx0XG5yZXN1bHRbL1F1ZXJ5IHJlc3VsdHNcXF0iLCJtZXJtYWlkIjoie1xuICBcInRoZW1lXCI6IFwiZGVmYXVsdFwiXG59IiwidXBkYXRlRWRpdG9yIjpmYWxzZSwiYXV0b1N5bmMiOnRydWUsInVwZGF0ZURpYWdyYW0iOmZhbHNlfQ) +![Example](./docs/query.svg) ## Features diff --git a/docs/query.md b/docs/query.md new file mode 100644 index 0000000..d463e69 --- /dev/null +++ b/docs/query.md @@ -0,0 +1,69 @@ +Use https://mermaid.live for generate SVG. + +```mermaid +graph TD +first("SQL Query +select * from orders +where user_id = ? and status = ? +limit 10 order by id desc +args = [100, 1]") + +first--->| Gorm Query |db["Gorm DB"] + +subgraph "Gorm" + db-->gorm_query + gorm_query["connPool.QueryContext(sql, args)"] +end + +subgraph "database/sql - Conn" + ExecContext[/"ExecContext"/] + QueryContext[/"QueryContext"/] + QueryRowContext[/"QueryRowContext"/] + gorm_query-->Conn + Conn(["Conn"]) + Conn-->ExecContext + Conn-->QueryContext + Conn-->QueryRowContext +end + +subgraph sharding ["MyConnPool"] + QueryContext-->router-->format_sql-->parse-->check_table + router[["router(sql, args)"]] + format_sql>"Format sql, args for get full SQL + sql = select * from orders + where user_id = 100 and status = 1 + limit 10 order by id desc"] + + check_table{"Check sharding rulesby table name"} + check_table-->| Exist |process_ast + check_table_1{{"Return Raw SQL"}} + not_match_error[/"Return ErrorSQL query must has sharding key"\] + + parse[["Parser SQL to get AST + + ast = sqlparser.Parse(sql)"]] + + check_table-.->| Not exist |check_table_1 + process_ast(("Sharding rules")) + get_new_table_name[["Use value in WhereValue (100) for get sharding table indexorders + (100 % 16)Sharding Table = orders_4"]] + new_sql{{"select * from orders_4where user_id = 100 and status = 1limit 10 order by id desc"}} + + process_ast-.->| Not match ShardingKey |not_match_error + process_ast-->| Match ShardingKey |match_sharding_key-->| Get table name |get_new_table_name-->| Replace TableName to get new SQL |new_sql +end + + +subgraph database [Database] + posts_other[("orders_0, orders_1 ... orders_3")] + posts_4[(orders_4)] + posts_last[("orders_5 ... orders_15")] + other_tables[(Other non-sharding tablesusers, stocks, topics ...)] + + new_sql-->| Sharding Query | orders_4 + check_table_1-.->| None sharding Query |other_tables +end + +posts_4-->result +other_tables-.->result +result[/Query results\] +``` diff --git a/docs/query.svg b/docs/query.svg new file mode 100644 index 0000000..cb056db --- /dev/null +++ b/docs/query.svg @@ -0,0 +1,10 @@ +DatabaseMyConnPooldatabase/sql - ConnGormGorm QueryExistNot existNot match ShardingKeyMatch ShardingKeyGet table nameReplace TableName to get new SQLSharding QueryNone sharding Queryorders_0, orders_1 ... orders_3orders_4orders_5 ... orders_15Other non-sharding tablesusers, stocks, topics ...orders_4Check sharding rulesby table nameParser SQL to get AST + + ast = sqlparser.Parse(sql)Format sql, args for get full SQL + sql = select * from orders + where user_id = 100 and status = 1 + limit 10 order by id descrouter(sql, args)Sharding rulesReturn Raw SQLReturn ErrorSQL query must has sharding keyUse value in WhereValue (100) for get sharding table indexorders + (100 % 16)Sharding Table = orders_4select * from orders_4where user_id = 100 and status = 1limit 10 order by id descmatch_sharding_keyExecContextQueryContextQueryRowContextConnconnPool.QueryContext(sql, args)Gorm DBSQL Query +select * from orders +where user_id = ? and status = ? +limit 10 order by id desc +args = [100, 1]Query results \ No newline at end of file diff --git a/images/example-scenario.drawio b/images/example-scenario.drawio deleted file mode 100644 index b113d78..0000000 --- a/images/example-scenario.drawio +++ /dev/null @@ -1 +0,0 @@ -7Vpdb5swFP01eZnUyAYCyWOXdp32IbXLw7qnyg0OsBlMjfO1Xz8b7AAhiUgbIGpGpBJfXxvjc869dtyeOQ5XdwzF/nfqYtIzgLvqmTc9w4CWYYubtKwziwOVwWOBq5xywyT4i5URKOs8cHFScuSUEh7EZeOURhGe8pINMUaXZbcZJeWnxsjDFcNkikjV+jNwuZ9Zh4aT2z/jwPP1k6E9ympCpJ3VmyQ+cumyYDJve+aYUcqzb+FqjImcPD0vWbtPe2o3A2M44nUauI8/XujT08sX7thfYz55AIuHK93NApG5emM1Wr7WU4BdMSOqSBn3qUcjRG5z60dG55GL5XOAKOU+3yiNhREK42/M+VrBi+acCpPPQ6JqZzTiqhJaqjymhLJ0BOYQyI+wZ2OTA9o7CcqU0Dmb4kNvrsiEmIf5AT9rA5XgOKYh5mwt2jFMEA8W5XEgRTZv46eaXjOG1gWHmAYRTwo930uDcFC6GdiKNEo1cLiF7XH+4ks2Al0qvEpuSvlyDHesV1ClQXLgVcAfJQf7EAxU+Zds1AfQVOWblSJpWlgXCveYBWJGMFO2hDP6BxeeA9KrwvYOKGm+kZIFWrwC9R0BwyZc4VKig/0yp7riKkkRvBYOcBiv8so0dutJzo3mLL2KJtuT9wQTGecN8EGGc0ZDcaPMxUzICSx9zLC4i6Qh/qZdAihAUyMUL5wNMuuqQt8cWcm7pR9wPIlRitlSpLctWgaEFOhhAzSCToU4EY1wlbPq5fQQFphxvDrMnyreqoFVlr5SPljm2crR0cEvZCrtd3qCmJeaUsya+h10qd9d6BypX7usXy2mUi9HaVrr10ahFFn0nMRZZNCdPjPtCoG65ITJ1V2l0R6pNx8BZgCZANWMAJtscvoIYIFqCICthgA4utQQYNUMAU6XIcDqOIXfUSaz9sRHzA0irw1twmcEsdFBdjaNsjg3Yi2I0xq2Kc7BydFXCzMidreSwsmcyL1N86DiAbRAda3ePKhbu63N7qsYcI02MbXfjqm5C9MsMT9l6fY0XcKt7L0nW9dL6u8xQuxK360GCJ2sLy97OzWzNwS7EW0nfTvNih2WxJ6vvJuR/7ks3juT/+Dc5D9sll6j0aixXHLxZHLOjUz6GOfkq80ZSni7q00AhqiT1eYAnNtyE+7/ESmJUVQLVWsXqv1+vwBl1td70qdV46caq1Uk9+8G/yN5cAt4bkjqg/Z2F+n5mVvpxK136LTtjA97jWbW9aKYn/Nnx6/5f0uYt/8A \ No newline at end of file diff --git a/images/example-scenario.svg b/images/example-scenario.svg deleted file mode 100644 index 83ebe74..0000000 --- a/images/example-scenario.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -select * from orders where uid = 100select * from orders where uid = 100orders 100000000 rows orders...Gorm ShardingGorm Shardingslow resultsslow resultsorders_000 100000 rows orders_000 10...orders_100 100000 rows orders_100...orders_999 100000 rows orders_999 10...fast resultsfast results............Text is not SVG - cannot display \ No newline at end of file