文题是一个错误,小众错误,或许和postgresql相关,或许和citus相关。然而这个错误在网络上只会有一个地方存在。
故事背景
错误的背景就使用 benchmarksql工具测试citus的TPCC性能。因为citus是PG的一个分布式插件,能将多个单机PG节点变成分布式数据库,这种分库分表的插件的使用需要一个额外的操作:建立分片规则。
在citus中,就是建分布式表,比如对 user
表基于 id
分片。
SELECT create_distributed_table('user', 'id');
TPCC规范涉及9张表,分为5个场景,表之间涉及多种join和事务更新,所以这个分片规则还不是那么好建。
我从citus的tpcc测试入手,搜索到同样的issue:https://github.com/citusdata/citus/issues/4126.
这哥们给了一套建分布式表的方案,但是测出来的性能太差了。不过人家跑通了呀。
于是我基于这位仁兄的建议建了如下分布式表:关于引用表,可以参考citus文档。
SELECT create_distributed_table('bmsql_config', 'cfg_name');
SELECT create_distributed_table('bmsql_new_order', 'no_w_id');
SELECT create_distributed_table('bmsql_oorder', 'o_w_id');
SELECT create_distributed_table('bmsql_order_line', 'ol_w_id');
SELECT create_distributed_table('bmsql_history','hist_id');
SELECT create_distributed_table('bmsql_customer','c_w_id');
SELECT create_reference_table('bmsql_item');
SELECT create_reference_table('bmsql_district');
SELECT create_reference_table('bmsql_warehouse');
SELECT create_reference_table('bmsql_stock');
然后使用benchmarksql测试时就会出现下面的报错:
22:05:39,296 [Thread-1] ERROR jTPCCTData : Unexpected SQLException in PAYMENT
22:05:39,296 [Thread-1] ERROR jTPCCTData : ERROR: cannot perform an INSERT without a partition column value
org.postgresql.util.PSQLException: ERROR: cannot perform an INSERT without a partition column value
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2198)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1927)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:561)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:419)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:365)
at jTPCCTData.executePayment(jTPCCTData.java:930)
at jTPCCTData.execute(jTPCCTData.java:99)
at jTPCCTerminal.executeTransactions(jTPCCTerminal.java:160)
at jTPCCTerminal.run(jTPCCTerminal.java:88)
at java.lang.Thread.run(Thread.java:748)
黎明的光辉
经过了一夜的思考,我决定冰释前嫌,重新上路。
首先,报错信息在google里搜索,结果发现只有一条完全匹配的信息:
这时我的内心是崩溃的,难的不是问题,而是孤独。
于是从这一条信息出发,发现这哥们也遇到了一样的问题,然而并没有人解答。
这真是悲哀,这条路走到了尽头,那么只有换条路了。
于是我继续从那哥们的ssue入手:https://github.com/citusdata/citus/issues/4126.
顺着开发人员的回答,我找到了官方测试benchmark的方案:https://github.com/citusdata/ch-benchmark.
这个仓库是基于 HammarDB测试框架开发的citus测试,里面的文件不多,我想肯定能找到建表语句。于是我一个个找,最终没想到是在 patch
文件里: https://github.com/citusdata/ch-benchmark/blob/master/HammerDB-patch/4.0.patch
经过阅读,提取出关键信息:
SELECT create_distributed_table('bmsql_customer', 'c_w_id');
SELECT create_distributed_table('bmsql_district', 'd_w_id');
SELECT create_distributed_table('bmsql_history', 'h_w_id');
SELECT create_distributed_table('bmsql_warehouse', 'w_id');
SELECT create_distributed_table('bmsql_stock', 's_w_id');
SELECT create_distributed_table('bmsql_new_order', 'no_w_id');
SELECT create_distributed_table('bmsql_oorder', 'o_w_id');
SELECT create_distributed_table('bmsql_order_line', 'ol_w_id');
SELECT create_reference_table('bmsql_item');
这就是最终的TPCC分布式建表语句。使用这种方式建分布式表,可以正确测试出结果。
圆满结局
其实,这个问题非常小,但是我突然意识到了一些更深层次的东西。
作为一个程序员,理解东西和解决问题并不是等价的,我并不清楚citus实现分布式表的细节,只知道分布式表和引用表的概念,再加上强大的搜索引擎能力,完全可以解决别人已经遇到过的问题。
所以,我只能是一个解决已有问题的程序员,而不是一个创造事物的科学家。
突然觉得自己也挺可笑和无奈的,程序员以为自己在创造产品,创造世界,其实大部分人不过是重复地创造*,重复地解决别人解决过的问题。
意识到这一点,我发现这是整个人类的问题,人类有了互联网,信息互联,触手可及。但是每个人从出生开始都需要不断学习才能获取这些知识,在时间的长河中,人类的生命昙花一现,何其短暂。却也能绽放出一些娇艳。
突然想到刘慈欣大师的科幻作品《乡村教师》,要是人类的记忆可以遗传,就不用老师呕心沥血了吧。
记忆不等于知识,知识不等于能力,解决问题不等于创造未来。
我笑一笑,合上电脑。