楼主: newkid

[精华] 出个SQL题:4皇后问题(新增马步问题在第7页)

[复制链接]
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
101#
发表于 2010-12-7 10:52 | 只看该作者
原帖由 newkid 于 2010-12-7 09:53 发表
差距这么大?在我这里是1.71和2.06秒。如果我把自己的写法的过滤提前并固定化,则提高为1.8秒,比你多了8次过滤。


嗯。
我的语句是直接生成8^8个记录,
你原来的语句是生成64^8个记录, 然后经过过滤只保留其中的1/(8^8), 剩余 (64^8)/(8^8) = 8^8个。

修改后的这个语句, 则是为每个64过滤成1/8, 相当于 (64/8)^8=8^8, 预先对每个64取8的开销几乎可以忽略不计了。

另外, 发现一个有意思的现象: 无论以上哪个语句, 如果加入no_merge提示, 性能都很好,在我这里都是2-3秒。

no_merge后, 所有的执行计划里的nest loop改成了merge join cartesian, 至于这样的执行计划为什么这么快, 没想明白。

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
102#
 楼主| 发表于 2010-12-7 22:48 | 只看该作者
原帖由 tree_new_bee 于 2010-12-7 10:52 发表


嗯。
我的语句是直接生成8^8个记录,
你原来的语句是生成64^8个记录, 然后经过过滤只保留其中的1/(8^8), 剩余 (64^8)/(8^8) = 8^8个。

修改后的这个语句, 则是为每个64过滤成1/8, 相当于 (64/8)^8=8^8, 预先对每个64取8的开销几乎可以忽略不计了。

另外, 发现一个有意思的现象: 无论以上哪个语句, 如果加入no_merge提示, 性能都很好,在我这里都是2-3秒。

no_merge后, 所有的执行计划里的nest loop改成了merge join cartesian, 至于这样的执行计划为什么这么快, 没想明白。

原来如此,我还在同情你的硬件配置呢,原来是查询计划的问题。我在11G下不用加任何提示就是MERGE JOIN CARTESIAN, 所以执行速度相差无几。
我把过滤提前造成的变化也很费解,从计划上看,不提前则一边连接一边过滤,其实每次也是过滤后再连接,但是就慢了0.2秒。

使用道具 举报

回复
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
103#
发表于 2010-12-7 23:17 | 只看该作者
原帖由 newkid 于 2010-12-7 22:48 发表

原来如此,我还在同情你的硬件配置呢,原来是查询计划的问题。我在11G下不用加任何提示就是MERGE JOIN CARTESIAN, 所以执行速度相差无几。
我把过滤提前造成的变化也很费解,从计划上看,不提前则一边连接一边过滤,其实每次也是过滤后再连接,但是就慢了0.2秒。


听你这么一说,郁闷了。 下载11g去。
不说性能了, 至少能玩玩model语法了。

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
104#
 楼主| 发表于 2010-12-7 23:20 | 只看该作者
原帖由 tree_new_bee 于 2010-12-7 23:17 发表


听你这么一说,郁闷了。 下载11g去。
不说性能了, 至少能玩玩model语法了。

MODEL在10G就有了,最值得玩的是递归的WITH子查询,买本我们的新书看吧,哈哈。

使用道具 举报

回复
论坛徽章:
10
CTO参与奖
日期:2009-02-20 09:44:20ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30迷宫蛋
日期:2012-05-07 10:55:58茶鸡蛋
日期:2012-04-19 16:08:262012新春纪念徽章
日期:2012-01-04 11:54:462011新春纪念徽章
日期:2011-01-04 10:24:02数据库板块每日发贴之星
日期:2010-12-19 01:01:02数据库板块每日发贴之星
日期:2010-12-13 01:01:012009日食纪念
日期:2009-07-22 09:30:00优秀写手
日期:2014-02-08 06:00:12
105#
发表于 2010-12-9 23:08 | 只看该作者
原帖由 newkid 于 2010-12-7 22:48 发表

原来如此,我还在同情你的硬件配置呢,原来是查询计划的问题。我在11G下不用加任何提示就是MERGE JOIN CARTESIAN, 所以执行速度相差无几。
我把过滤提前造成的变化也很费解,从计划上看,不提前则一边连接一边过滤,其实每次也是过滤后再连接,但是就慢了0.2秒。



装上了11g,  11g下执行速度确实非常快。

看来要仔细研究下不同环境的执行计划了。

[ 本帖最后由 tree_new_bee 于 2010-12-9 23:15 编辑 ]

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
106#
 楼主| 发表于 2010-12-10 00:11 | 只看该作者
回到顶楼的问题,我当时在第四页37楼的解答用的是十进制相加来变相实现BITOR的方法。因为十进制NUMBER在ORACLE中有位数限制,无法做49位的加法,所以不得不拆成两截来相加。
我的朋友Frank Zhou给出了用UTL_RAW.BIT_OR的方法。我当初不是没有想过,但是因为它的参数和返回值都是RAW的,转换很麻烦。其实不需要做二进制转换,直接用16进制,这样就可以按字符串来解析结果。

比如 BITOR(1000,0010), 不需要把操作数变成8和2, 再把返回值又逐位求出来。就用 RAWTOHEX(UTL_RAW.BIT_OR(HEXTORAW('1000'),HEXTORAW('0010'))),得到的仍然是0和1的字符串。内部做的是4096和16的BITOR操作但不影响我们的判断逻辑。
用ORACLE的隐性转换,连HEXTORAW和RAWTOHEX都可以省掉。要注意的是UTL_RAW.BIT_OR总是返回偶数位长度,奇数则左边会补一个零,所以我们要做49位运算时必须从第二位取结果。


WITH c AS (
   SELECT ROWNUM id, MOD(ROWNUM-1,7)+1 x,CEIL(ROWNUM/7) y FROM DUAL CONNECT BY ROWNUM<=49
   )
  ,cells AS (
   SELECT c1.id,c1.x,c1.y
         ,REPLACE(SYS_CONNECT_BY_PATH(CASE WHEN c1.x=c2.x OR c1.y = c2.y
                                                OR c1.x-c2.x IN (c1.y-c2.y,c2.y-c1.y)
                                           THEN '1'
                                           ELSE '0'
                                      END,',')
                 ,',') cover
     FROM c c1, c c2
    WHERE level=49
    START WITH c2.id=1
   CONNECT BY c1.id = PRIOR c1.id AND c2.id = PRIOR c2.id+1
   )
SELECT c1.x||c1.y||'-'||c2.x||c2.y||'-'||c3.x||c3.y||'-'||c4.x||c4.y AS result
  FROM cells c1,cells c2, cells c3, cells c4
WHERE c1.x BETWEEN 1 AND 4
       AND c1.y BETWEEN 1 AND 4
       AND c1.x <= c1.y
       AND c1.id < c2.id AND c2.id < c3.id AND c3.id < c4.id
       AND SUBSTR(c1.cover,c2.id,1)='0'
       AND SUBSTR(c1.cover,c3.id,1)='0'
       AND SUBSTR(c1.cover,c4.id,1)='0'
       AND SUBSTR(c2.cover,c3.id,1)='0'
       AND SUBSTR(c2.cover,c4.id,1)='0'
       AND SUBSTR(c3.cover,c4.id,1)='0'
       AND INSTR(SUBSTR(UTL_RAW.BIT_OR(UTL_RAW.BIT_OR(UTL_RAW.BIT_OR(c1.cover,c2.cover),c3.cover),c4.cover),2),'0')=0
;

[ 本帖最后由 newkid 于 2010-12-10 00:13 编辑 ]

使用道具 举报

回复
论坛徽章:
13
2010广州亚运会纪念徽章:轮滑
日期:2010-09-03 12:44:53马上有房
日期:2014-04-04 13:51:34马上加薪
日期:2014-04-04 13:35:40优秀写手
日期:2014-03-14 06:00:13夏利
日期:2013-08-05 18:32:18复活蛋
日期:2013-06-25 17:22:592013年新春福章
日期:2013-02-25 14:51:24蛋疼蛋
日期:2013-01-08 18:08:502011新春纪念徽章
日期:2011-02-18 11:43:33生肖徽章2007版:兔
日期:2011-01-20 12:58:49
107#
发表于 2010-12-13 23:31 | 只看该作者
强帖留名,学习

使用道具 举报

回复
论坛徽章:
4
2010广州亚运会纪念徽章:体育舞蹈
日期:2011-03-15 16:51:23SQL大赛参与纪念
日期:2011-04-13 12:08:17鲜花蛋
日期:2011-09-04 06:53:45双黄蛋
日期:2013-06-20 14:32:04
108#
发表于 2011-3-7 02:12 | 只看该作者
关于 8 皇后的问题

皇后只可能分别在 1-8行。这个应该是首先反证明出来的结论(列的情况也一样)。

[ 本帖最后由 LeftJoin 于 2011-4-27 00:04 编辑 ]

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
109#
发表于 2016-11-8 11:26 | 只看该作者
newkid 发表于 2010-12-10 00:11
回到顶楼的问题,我当时在第四页37楼的解答用的是十进制相加来变相实现BITOR的方法。因为十进制NUMBER在ORA ...

原来你早就做过长2进制数的拆分

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
110#
发表于 2016-11-8 12:30 | 只看该作者
lastwinner 发表于 2010-8-20 09:29
边缘部分的,可设想将此棋盘扩大为9倍原始大小
原始棋盘在中间,周围八个方向上棋盘的棋子摆放都与 ...

会漏答案吗

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表