数据库编程大赛:一条SQL计算扑克牌24点
12月27日,NineData和云数据库技术社区主办,华为云、火山引擎、开源中国、云和恩墨、TDengine、云猿生数据、DORIS、ITPUB等协办单位和媒体,共同举办了本次《数据库编程大赛》。大赛题目「用一条SQL给出扑克牌24点的计算表达式」。
以下亚军选手柳胜勋的参赛情况的介绍:
参赛选手:柳胜勋
个人简介:PingCAP/TiDB研发工程师
参赛数据库:MySQL
性能评测:百万级数据代码性能评测 0.88秒
综合得分:87.2
以下是柳胜勋选手的代码说明思路简介:
1. 生成存在的组合的答案集,转成json,并压缩,因为不压缩SQL过长。
2. 在SQL中,解压答案并转换成临时表,然后使用GROUP BY处理,强制走HASH JOIN。
3. 使用LEFT JOIN算出结果。
以下是柳胜勋选手的算法说明,结尾附完整SQL:
算法说明
1. 题解分析
这个题目,如果使用程序求解,本质上是一个搜索题,可以再加上记忆化来优化。
需要处理多行,所以时间复杂度为 O(n*X),X就是每个组合的计算时间。搜索复杂度不低,使用SQL的话,处理并不简单。
然而,这里有个不错的切入点,我们发现题目的答案其实并不多,去重后的正确解实际上只有566种。所以,可以预先把答案计算出来,直接放到SQL里。
2. 尝试
正好MySQL支持JSON操作,所以答案可以用JSON存放,然后通过Key查询。此外,因为给出的4个数字顺序是不确定的,所以还需要做个排序。
这里采用的办法就是将4个数字排序。MySQL没有排序函数所以这里有点麻烦。
好在只有4个数字,可以直接输出 最小值,除了最小值以外的最小值,除了最大值以外的最大值,最大值 来解决排序问题。
一开始,我是直接将答案使用 JSON_EXTRA 输出,但发现性能并没有非常好,应该是因为MySQL没有过多优化JSON的处理。所以后续还做了一些别的尝试。
3. 优化
3.1 LEFT JOIN
使用 JSON_TABLE 将JSON转成一张临时表,然后LEFT JOIN主表。但这样的性能依然没有起色,这是因为MySQL优化器的处理问题,使用了NLB。
解决办法是,将临时表 Group By一下。LEFT JOIN 才会使用HASH JOIN。
3.2 SQL过长
第二个问题是SQL过长,答案的长度已经接近10K,加上其它部分,就超过10k了。所以还需要对答案压缩编码,然后在SQL中解压。
3.3 编码
数字比字符串的匹配要快,数值大小为1-10,可以将有序的数字用10进制处理再相加。
4. 答案
以下是最终的答案,为了方便阅读,这里省略了结果集。
SELECT `cards`.*,
v AS result
FROM `cards`
LEFT JOIN(
SELECT k,
v
FROM JSON_TABLE(CONVERT(UNCOMPRESS(UNHEX('结果集编码')),CHAR),'$[*]' COLUMNS(k int PATH '$.k',v varchar(32) PATH '$.v')) AS tp
GROUP BY k
) AS kv ON((LEAST(c1,c2,c3,c4) -1) *1000+(IF(LEAST(c1,c2,c3,c4)=c1,LEAST(c2,c3,c4),IF(LEAST(c1,c2,c3,c4)=c2,LEAST(c1,c3,c4),IF(LEAST(c1,c2,c3,c4)=c3,LEAST(c1,c2,c4),LEAST(c1,c2,c3)))) -1) *100+(IF(GREATEST(c1,c2,c3,c4)=c1,GREATEST(c2,c3,c4),IF(GREATEST(c1,c2,c3,c4)=c2,GREATEST(c1,c3,c4),IF(GREATEST(c1,c2,c3,c4)=c3,GREATEST(c1,c2,c4),GREATEST(c1,c2,c3)))) -1) *10+GREATEST(c1,c2,c3,c4) -1)=k;
其中有一个优化小技巧:results_features 与 cards_features 两张表都先按照求得的 feature排序,最终在 JOIN 的时候就会用 merge join 代替 nest loop,执行效率更高。经过优化后,128 万行测试数据在我电脑上之需耗时 0.7 秒。
5. 总结
本文详细地解释了我参与比赛时的解题过程,但由于能力有限,并且最近事情较多,并没有做过多的优化。希望有更优方案的小伙伴不吝赐教!
参赛完整SQL:
SELECT `cards`.*,
v AS result
FROM `cards`
LEFT JOIN(
SELECT k,
v
FROM JSON_TABLE(CONVERT(UNCOMPRESS(UNHEX('773A0000789C655B49B2ECB80DBCCB5B5549CDD013090EEAAB74F804DE7BE3F0DD0D502232A11FB5138212494C8904EA9FFFFEFCFBE7EF52E4FAEBE73F3F7FFF48FAD474FE7E37F9F9DF5F53769E39DFB2BC7DCA5EBE5B2651B94565FBE45DF6FC259140B4D51444F516A9A0EC2DBEB02DD15EF61E45FDD9C6AEDB185134D60ECB7E91A0F647308EB645C1F3B2B60FFDB9A0B6F1ACF8F4FDFA6ED7D17C0DEE683F7FF78AB7895C8FA46E7679C7F9BB44A5FB0EB6CF48D72E5F123D7BD01D6CE3F00BCF2EF8A824E9490B89F0BA2B88CEB3355753DF3B5D7829EDD9DFE7FC4D7AA91FA17D9CEB5875CF9BCA4FBF0BBF3DDDB96AE9DA1B89D6FDE9CEA798F6B1F4B475BE5ADDFBDAC5B0EF8CEF81732D3BBA0D4CB61312192EAAA6103A71BDD6979AA9840C622924DB731641899B5D46DD4F5C5375DDB7FD4A17F94019AEFA6BBED1B72775196CD39775D695D4EAAFD3EB53BF2A5F1C2B28B244D1B28BE353D23820125977DBD3500BACD8BAAB4395215FDC9F1ECA25579284E3BAABA9A7A9A64E3CAFE4D38DDEE52E6DCEF9355387A4B803B2F6C831557D57785727C92035E4B2AE46F4F9B5171CA52E9FD5C3F051CA52823EEF4958A76369EE9A9A4BF0B2650865AB3B9B7D7E99FD47B7C097762D0D145D462165B9DFA76F5DF776707858D1619ADC97BE95974FCC3BF8C561A5BB578E607167F32BED76243C5FA6A16E3C763280F5A691D4464368AF757950338F6C5B839B780CD20D1C232C0A567DB2EA106E8B865B1C1316AD46C5CA76EBD4B01D5E5539BEB040865F8C29942D6AAD291A0E4682667276557F4C6907E5A2ECC7D15529E4A2BCAC4A73D4D6A14F0F13BAE99D4FE90B9A7954A2E856E1527A6BE4D1A707C531F58C5DEBA2E73325D9EDF0DB966A66F21C14116589AA1E8662AF0AC67283B655B2CD7516BB4DB2A6524298E488726A745D81234717D0CF788AAEAFC42E9E9D344CB2DB2C7DF6DB41790942841AE1378806892ECE75CBA275633346242470F1B3E68D3D277E8743A408F27AC68ADA3CA15AA6359FA2AF347A5BE78BF3DB31490B21AF7A7E314F248D22F36C57E2EBE96C39534983DE57FA7A9F5846282C5AD1CD4000E7D3BC24325312ED3CAFD7E91A0D059A9578EF0BE7E9A72A65C6026838BF4492B636676E42CF577C578F4FE510DE74F1ADE9AA2F85F1B2BE2F9BEC75A7D3ACD7DD9FD7D8176E61456B3924A4ED735C9E312676E0405EE15D21FB5D6E74C92EE7F7CBE0D06DC890F55111C956C41E96B51889C88AF1AA07C53C9F4EF72D1265BCAE75DEC8981BE9B4910A6B6EBB83070D28CB9A2D06DAA2428BC805EA516198CBCEE5B673BE26389A85157CA8FAB95A9AF09AECBCBA51B4101F3CEBCB8C9DF41DB53C98650D81B0F80DF66DDE130CE604225283BD0EFED2CA39876C6323C8B814A5E7D4280D5408A4A2CE39120BDCFF06AF687DB9F3D04FDF689C4A0F57AC25D64E8A75A4DB3474D9321295E170C94238E5AFE2F9D0FC36643D7275C36507AFAAB4AAA5B0CA75F4791567E4EDE6A271D5428D1A214C4F48A4DD4F35622AF7EC334B120EA1ED822A18D7B7EE69644438074355C4ACAE4451C0C1A162BCEB65F8A8CE36ADC100B515D53BA2564505C18A5FE6E9ED404DA42247066ADDF0084D09EB0A8EBA712E2D408DBBE153D8D0E9686A62A9119417AB8A0D6AF0BAD6D2EC9528D12312CE30A9F8990AC7650C96471A1BB82BD5E267E55209B17AB75524A0771912E5FA14219C2A91CC55A6EA00EEED31DF720ECC430067345A5DC7459805A58B229060845E213C591465AE2E2B5836EBE6CC491B4597E545CEA415814EDE258456C88E0314C493AF4885D17D0CC05516A1903322A1F2462ABE66B08B4AE47301A55D8F70F1B92B9553F6A34266B9925DC8D199D5A928770D14B3EDC5F731D782CB308F896BB86E6DF4A50A37DB67E9DA58D4B10923417CEF5E4ECD4223C449C0A55BCD21BA22BCBE8804BC7056671CF1967F5A5DBF87949F3D4AA9ACEF21AE6845BC90788A5C9517369761010E056E4D32592CF6284F807A795CA49D2580B91C122081C37D0452CC099AD4E2914E72F8192602A1E72EFF993E1FD779F4150B2E619507848F846A8123698B18DE11CE54E361CA22D84429B4CF144A5EB2AE771A866A3F213AD4259B96160A44C54690DD1F842B17AA9F3FF3C6C0E2096C7B9FD65D29027898B64A84EB9A8E52648494ADF8C85388D61C4807224B50A700B9A57909DF2D7C92DFD5B60EF5108256FCD3BA4081E6346813CE4CDAB2460687FBBD293226469C99E8916B2597B42A6A6F0C78DC25270AC725892FBBC375543390D74C19C873806A163D99C05BA735507C4502CFE38C416D4A400D3CEC3E532DC1B8CAF692983FCB79D9A7A2A7C064E6E2C62911D6388EDD23DB23A4C1A3BE9C1584FDCD789035BB515AC0E044B12E759247CC4394F52549531384919CF67E7484DB761DA9606C9DC8EDCA05BAD56464798EFBB26554DB05F48AA2E246F404C3459035C58A145EE5ACDC146CBC6A95431A6F5B10AC50A7D02BAC51BF75B51B8A22B4E6D4B1563C47A08E3DDA6E166D8946A10462D8221E17E15B18AEE5B6BCBD4F6F2F24706AB8B36673088A4728754B808B8CDAB357C177400C394C63BA971C6695C4A92E4DD89D06F3AAC03C1AC098CB113E51E584D85CE33D5D6105F4AD0BC8F984A85B2B8E2F2E9CD155B9BD996023F2F5646C7EA9CE3D8B232809F9FA7452245BCA1B078B9C5AFFC8AB8BE5AC84BD2F52642BC5E6C9A4B0C051E816D32BEA24F3A617157BC154D5B6E0B528BB74D3BA8E8880E1F1E962E63D4748A817BE936A075C7D420DCEFE1739BBC46C9D81A04AAA112565B469EEBA886C8FA8B2501765AFA5EA2DA1ED7B9DD72DF6073C4664C515CD8FA28A860146C114DC2C5147C6D0B371E439F31258BFA133C41467A0AD906A5CCE89B02882AEE6B1B2BF7870EE986DB1B85F675209433F4DEC41C12DE045F42985CDBCB8E79ADB5864215D741C969A11B5A2E29EA99170477102C4BA38464AD0EB065E478CBB54ECE08E6D0D2227B5669F827DDA7B76C6E351BDE90D3B7BDEF833DC43AB5F9670FD12283C9CC65A1B3D7129D7B0AA872A4FEBB5ECE1413D890A8E9C57562FFAB87077C19BF046CB08BB514613DE6C81058BE5D9ADBBC182E6C653BE2FBE2467379FA2308ACB4CC4C21C7AF3C581DC04C8EFFE93336E9F33B563108AE22B67AE9C78C7499AE239D8E37A84EEA0385B7073B024614C21D498736AD16C3EACE1127D849DA1429F7D4B867D2BC3291AD37A9A6E14BDA4747193A7783A9F1D062EED4A43A731BDDC2EE683126863CFF5461E106DE579D13893710CDAB6E3F6A1FA265CEC25ACC5176E5674FFFE08303697465A63D80228618C306780C61A0866E8284C6BA4D9A7A7ADB1463568178E97AF218800B814A12031B7108673980939026D7D82DB3822BFA2229F57691C6BB303CF7627163A19E0AA095E588DA0F1E0B692031493BC108FE3BBEB0825A808D55E33F932B50FD24BC2308623945B12FCC2818D6859F8C941D268834C6B0356EC3187492CA26AE83779A5F4423C6B6FE70C5C35943D2CA2C8EEC1EE7C821D03A827C7CF50C77CE932F1D98B2282C9EF537715F64559F2D53C2BC88796260281506A688E37E665995B081D09269A5F5C6EE5C6BD255FA210403DCDC92642BF4019D690F80D8C04C53BB52FDA8423ED76CF2FD1977C7FA9C72884DCAB476D54C31127324201D5079E5389246882CFCBC16132CE52F6D844C944D896E8C7393B280E841D48A31B609397200CCBC60DC4D373B865D7ADC4CF781FB598F57207253B74B4BE4B68AE6480C7384A97B1EFD90BE031226FA258FB95774E9DFD8725A31B027F76535D14D196EE761BBD2024DAB085FE6A3321BFA5D7349FA7CB62252E040DA8BBBF5CFF85A163AF170EA8F03185112DC63301C7FBE5DD634B3195B68B77C2C832E8F7FBE25E0872CD2B244983A46F8496D7915BFABCC60CDC5C9E2F4558E3A9CE42FB11309727DC191D62895C4829124AE4931A971691AF50C839F537AB2BE61EB8C31DA606D62EAEA3C456672674F3474C46AFD37A2A17B55C0A2D9377F7D4D19C21402ED4CBAB99CEFD1DF05E37BB45978141C1EBE60CC9155654522CC578A6825CB7A018474608A11AE7142A68A9D8FAA7058A88D0965921AB183A8E6C5446ED31C958A88A3870CB02044501B7E47E1B20221DCA3A2AAF121EB03BD41E60B2554D110E1786464942D7EC15BD8942AA3457A0E1F10A65E072043523CEFC48CA26784D583828A82FCF42F3E6282F76A921873EBE8AE44644423A43E39330E936E7ACA0C5B306EF69A10D87E2B273CF3FFBA4AFDCFD7130D6E3857EAFC85A10177984CDE718764BECDB3AB769752CEA3AF0A48F9F520387EBA763F0A9240C78D638C18C124A921CA0FC32819767749DE7E17830B4C65E51381717E819031F762E2AB54149CE7B877777108F96CC686CBC8631EF302A9DBD99F519AB366646DEEF49D3316BEB04E0CF863D180E6034B0BC38499437397882B7A39F1E770F9FF2B95EB18FB144C2AA1A6510C67856D0BF7B7A0664EF1E99721C123D0184338F957AC996B787E4210721494821803173E215C01E41EE7CA745B0F1BBDC4C011CCE83F0DCF32FA7241A787F423E0F02ADCA6730A3E53DBB3E078728FFC6C17F4EBFDC0A32AEBE06AA1EED87390484AD4B45275AC3F7C53EFF08CEED8F2847DBE8610A41A8DD682E30808A0AF1AFCF9C0D697D29AA454CB78C5C1FE6973E7CDCAE3CD3FD34ECFC6C7C8EAB1003E313C0FB3D17403D5CDA778A93CE853BA123FC2120F874D8768C898C351878C512A3BEFF9F11823D419BD94B209711EAD8D73F7A488CD9666547D520C8F239F247FD64AE6B02B82D60507A7AC3CA46F315D696C5DCA1538353918429730DF19E317BE5B17DDB0425F4D08F8FCC45A6F194A3C57F63902E0D99451159EE11FE6F4393E36635AC68C091730FA552E6D195F00706FC23444BD3A3856E640520993B672EDDEBD9C190AD78E6D335775B83DFC7A0A345D57B126BDCBD93F7E46BC2C502288BA6D1D7E42630A0C4467445B838EE910CE8318C2F07334337AE4FB2FD97272E19C9CFBFBA9008584FC26C4271CE78EEBE87EEACA354CB619543FB00CD69CD5E4EF6F0AB3BE6A32C7B0DCEF3A8F249FFA9D85E837B281B26770C4017EC8FB123C30AA645783221768E9776FBA35D1CE8A282F696F11F41301F31FD866CCCFFA362502EC49713C45A7E55639825B744CB231A6D651D8928A4B5D862EC34D55C00D625FC258926C655C434BD17D53744666A6F199E6C12D354AE012EB6F0D735A70AEEB8CE229CB5840192ECB3B473CC3676597C027766315E23B4A67E8308B4A8AEE2626B3D9F388862149E33219A79DEBB30B74F5E29EF5413E8B377B6A6299AF228FC5FFF078D6ADD84')),CHAR),'$[*]' COLUMNS(k int PATH '$.k',v varchar(32) PATH '$.v')) AS tp
GROUP BY k
) AS kv ON((LEAST(c1,c2,c3,c4) -1) *1000+(IF(LEAST(c1,c2,c3,c4)=c1,LEAST(c2,c3,c4),IF(LEAST(c1,c2,c3,c4)=c2,LEAST(c1,c3,c4),IF(LEAST(c1,c2,c3,c4)=c3,LEAST(c1,c2,c4),LEAST(c1,c2,c3)))) -1) *100+(IF(GREATEST(c1,c2,c3,c4)=c1,GREATEST(c2,c3,c4),IF(GREATEST(c1,c2,c3,c4)=c2,GREATEST(c1,c3,c4),IF(GREATEST(c1,c2,c3,c4)=c3,GREATEST(c1,c2,c4),GREATEST(c1,c2,c3)))) -1) *10+GREATEST(c1,c2,c3,c4) -1)=k;
《数据库编程大赛》下一次再聚!
感谢大家对本次《数据库编程大赛》的关注和支持,欢迎加入技术交流群,更多精彩活动不断,我们下次再相聚!地址:数据库编程大赛- SQL编程-数据库大赛-NineData-玖章算术