Day 42 A. Pashmak and Garden

该编程问题要求根据已知的两个正方形顶点坐标,判断能否形成一个正方形,并输出另外两个顶点的坐标。输入包含两个点的坐标,程序会检查它们是否能构成一个边长相等的正方形。如果可以,它将打印出剩余的两个顶点;否则,输出-1。示例展示了不同情况下的输出结果。

Problem
Pashmak has fallen in love with an attractive girl called Parmida since one year ago…

Today, Pashmak set up a meeting with his partner in a romantic garden. Unfortunately, Pashmak has forgotten where the garden is. But he remembers that the garden looks like a square with sides parallel to the coordinate axes. He also remembers that there is exactly one tree on each vertex of the square. Now, Pashmak knows the position of only two of the trees. Help him to find the position of two remaining ones.

Input
The first line contains four space-separated x1, y1, x2, y2 ( - 100 ≤ x1, y1, x2, y2 ≤ 100) integers, where x1 and y1 are coordinates of the first tree and x2 and y2 are coordinates of the second tree. It’s guaranteed that the given points are distinct.

Output
If there is no solution to the problem, print -1. Otherwise print four space-separated integers x3, y3, x4, y4 that correspond to the coordinates of the two other trees. If there are several solutions you can output any of them.

Note that x3, y3, x4, y4 must be in the range ( - 1000 ≤ x3, y3, x4, y4 ≤ 1000).

Examples
input
0 0 0 1
output
1 0 1 1
input
0 0 1 1
output
0 1 1 0
input
0 0 1 2
output
-1

题目大致意思为:给出两个点的坐标 求是否能够成一个正方形 如果能则输出另外两个点的坐标 如果不能则输出-1

#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<stdio.h>
#include<limits.h>
#include<cmath>
#include<set>
#include<map>
#define ll long long
using namespace std;
int main()
{
    int x1, y1, x2, y2;
    cin >> x1 >> y1 >> x2 >> y2;
	int dx = abs(x1 - x2);
	int dy = abs(y1 - y2);
	if (dx != 0 && dy != 0)
	{
		if (dx != dy)
		{
			cout << -1 << endl;
		}
		else 
		{
			cout << x1 << " " << y2 << " ";
			cout << x2 << " " << y1 << endl;
		}
	}
	else
	{
		cout << x1 + dy << " " << y1 + dx << " ";
		cout << x2 + dy << " " << y2 + dx << endl;
	}
    return 0;
}



HCP.HR_CARDING和FINGER5.FGT_FILE两表的数据量达几百万万,如下SQL超半小时也无法执行出结果,请协助优化SQL提高执行效率,并最后提供完整SQL:WITH FGT_FILTERED AS ( SELECT /*+ MATERIALIZE */ FGT10 AS BPM_ID, FGT02, TRUNC(FGT02) AS FGT_DAY, SUBSTR(FGT08,3,1) AS STATUS_RAW -- 预计算减少重复调用 FROM FINGER5.FGT_FILE WHERE SUBSTR(FGT08,3,1) IN ('1','2') ), A AS ( SELECT /*+ INDEX(A IDX_HRCARDING_BPM) */ A.PSN_ID, A.PSN_SEG_SEGMENT_NO, A.CDAY, A.INTIME, A.OUTTIME, A.DAYHOURS, A.SHIFT_ID, C.SHIFT_NAME, HCP.SF_BPM_ID_GET(A.PSN_ID,9) AS BPM_ID, CASE WHEN C.SHIFT_NAME LIKE '晚班%' -- 修改LIKE条件为左匹配 THEN A.CDAY + 1 + INTERVAL '12:00' HOUR TO MINUTE END AS NIGHT_SHIFT_END FROM HCP.HR_CARDING A INNER JOIN HR_SHIFT C ON A.SHIFT_ID = C.SHIFT_ID AND A.PSN_SEG_SEGMENT_NO = C.SEG_SEGMENT_NO WHERE EXISTS ( SELECT /*+ HASH_SJ */ 1 FROM FGT_FILTERED F WHERE F.BPM_ID = HCP.SF_BPM_ID_GET(A.PSN_ID,9) ) ), B AS ( SELECT STATUS_RAW AS STATUS, FGT02, BPM_ID, FGT_DAY, ROW_NUMBER() OVER ( PARTITION BY BPM_ID, FGT_DAY, CASE WHEN STATUS_RAW = '2' THEN SIGN(FGT02 - (FGT_DAY + 0.5)) END ORDER BY FGT02 DESC ) AS RN FROM FGT_FILTERED ) SELECT /*+ PARALLEL(4) */ A.PSN_ID, A.PSN_SEG_SEGMENT_NO, A.CDAY, A.INTIME, A.OUTTIME, A.DAYHOURS, A.SHIFT_ID, A.SHIFT_NAME, MAX(CASE WHEN B.STATUS = '1' THEN B.FGT02 END) AS INACTUAL, MAX(CASE WHEN B.STATUS = '2' THEN B.FGT02 END) AS OUTACTUAL FROM A LEFT JOIN B ON B.BPM_ID = A.BPM_ID AND B.RN = 1 AND ( (A.SHIFT_NAME LIKE '白班%' AND A.CDAY = B.FGT_DAY AND B.FGT02 BETWEEN A.INTIME AND A.OUTTIME) OR (A.SHIFT_NAME LIKE '晚班%' AND A.CDAY = B.FGT_DAY AND B.FGT02 BETWEEN A.CDAY AND A.NIGHT_SHIFT_END) ) GROUP BY A.PSN_ID,A.PSN_SEG_SEGMENT_NO,A.CDAY, A.INTIME,A.OUTTIME,A.DAYHOURS,A.SHIFT_ID,A.SHIFT_NAME;
最新发布
03-21
<think>嗯,用户给了一个SQL优化的问题,需要处理两个大表HCP.HR_CARDING和FINGER5.FGT_FILE,数据量都达到几百万甚至更多。当前的SQL执行超过半小时还没结果,得帮忙优化。首先,我需要仔细看看这个SQL的结构,找出可能的性能瓶颈。 首先看CTE部分,FGT_FILTERED这个公共表表达式里,从FGT_FILE表筛选了FGT08字段的第三个字符是'1'或'2'的记录,并且做了TRUNC和SUBSTR操作。这里可能会有全表扫描,尤其是数据量大的情况下,SUBSTR(FGT08,3,1)的条件可能导致索引无法使用。或许可以考虑在FGT_FILE表上建立函数索引,比如SUBSTR(FGT08,3,1),这样条件过滤会更快。 接下来是CTE A,里面有一个EXISTS子查询,关联到FGT_FILTERED。这里用到了HCP.SF_BPM_ID_GET函数,这个函数如果被频繁调用,尤其是在几百万数据的情况下,可能会导致性能问题。另外,INNER JOIN HR_SHIFT表的时候,是否使用了合适的索引?用户已经加了提示/*+ INDEX(A IDX_HRCARDING_BPM) */,但需要确认这个索引是否覆盖了连接条件和WHERE子句中的字段,比如PSN_ID和SEG_SEGMENT_NO。还有,LIKE '晚班%'这里应该是有索引的,但左匹配可能还好,如果SHIFT_NAME有索引的话。 然后是CTE B,里面用了ROW_NUMBER()窗口函数,按BPM_ID、FGT_DAY和条件分区,然后按FGT02降序排列。这里的分区字段是否有合适的索引支持?如果没有的话,排序可能会很耗时。可能需要在FGT_FILTERED上建立组合索引,比如(BPM_ID, FGT_DAY, STATUS_RAW, FGT02),这样窗口函数的分区和排序可以更快。 最后的SELECT部分用了LEFT JOIN和GROUP BY,可能涉及大量的数据聚合。这里用了PARALLEL提示,但可能需要调整并行度,或者检查是否有更好的聚合方式。另外,MAX(CASE ...)可能需要更多的计算资源,如果数据量太大,可以考虑提前过滤或预处理。 整体来看,可能的优化点包括: 1. 为FGT_FILE的SUBSTR(FGT08,3,1)建立函数索引,加快过滤速度。 2. 检查HR_CARDING表的索引是否有效,尤其是HCP.SF_BPM_ID_GET函数的结果是否可以被索引,或者是否可以将该函数的结果物化到表中,避免重复计算。 3. 确保HR_SHIFT的连接条件有合适的索引,比如在SHIFT_ID和SEG_SEGMENT_NO上的索引。 4. 优化EXISTS子查询,可能将FGT_FILTERED物化后使用HASH JOIN,或者转换为JOIN方式。 5. 窗口函数的分区字段可能需要索引支持,减少排序时间。 6. 最后的JOIN条件是否可以利用分区或索引,减少比较次数。比如,将B.RN=1的条件提前过滤,减少JOIN的数据量。 7. 考虑将一些计算逻辑提前,减少重复计算,比如在FGT_FILTERED中预计算TRUNC(FGT02)和SUBSTR(FGT08,3,1)。 8. 检查执行计划,查看是否有全表扫描或高成本的步骤,针对性优化。 另外,用户提到使用了MATERIALIZE提示,但可能需要确认是否真的需要物化临时表,或者是否可以通过其他方式优化。数据量大的情况下,临时表的存储和读取也可能带来开销。 还有,函数的调用HCP.SF_BPM_ID_GET(A.PSN_ID,9)可能在WHERE子句和SELECT列表中被多次调用,是否可以将其结果存储到临时表中,避免重复调用?比如在CTE A中预先计算这个值,并在EXISTS子查询和后续JOIN中使用这个预先计算的值,减少计算次数。 最后,可能需要调整并行度,根据数据库的配置和资源情况,适当增加或减少并行进程数,避免资源争用。 综合这些点,可以逐步修改SQL,测试性能,查看执行计划的变化,找到最有效的优化方法。</think>我将分步骤为您分析优化方案,并提供完整的优化后SQL: 一、性能瓶颈分析 1. 函数调用过多:`HCP.SF_BPM_ID_GET`在WHERE和SELECT中被多次调用 2. 无效索引使用:`SUBSTR(FGT08,3,1)`条件无法使用普通索引 3. 窗口函数效率:`ROW_NUMBER()`分区条件复杂 4. 连接条件复杂:存在多个OR条件关联 二、优化方案 1. 索引优化: ```sql -- FGT_FILE表创建函数索引 CREATE INDEX IDX_FGT08_STATUS ON FINGER5.FGT_FILE(SUBSTR(FGT08,3,1)); -- HR_CARDING表创建复合索引 CREATE INDEX IDX_HRCARDING_MAIN ON HCP.HR_CARDING(PSN_ID, PSN_SEG_SEGMENT_NO, CDAY); ``` 2. 改写后的完整SQL: ```sql WITH FGT_FILTERED AS ( SELECT /*+ MATERIALIZE INDEX_FFS(F IDX_FGT08_STATUS) PARALLEL(4) */ FGT10 AS BPM_ID, FGT02, TRUNC(FGT02) AS FGT_DAY, SUBSTR(FGT08,3,1) AS STATUS_RAW FROM FINGER5.FGT_FILE F WHERE SUBSTR(FGT08,3,1) IN ('1','2') ), PSN_BPM_MAP AS ( SELECT /*+ MATERIALIZE */ A.PSN_ID, HCP.SF_BPM_ID_GET(A.PSN_ID,9) AS BPM_ID FROM HCP.HR_CARDING A WHERE EXISTS ( SELECT /*+ HASH_SJ */ 1 FROM FGT_FILTERED F WHERE F.BPM_ID = HCP.SF_BPM_ID_GET(A.PSN_ID,9) ) GROUP BY A.PSN_ID, HCP.SF_BPM_ID_GET(A.PSN_ID,9) ), A AS ( SELECT /*+ INDEX(A IDX_HRCARDING_MAIN) USE_NL(C) */ A.PSN_ID, A.PSN_SEG_SEGMENT_NO, A.CDAY, A.INTIME, A.OUTTIME, A.DAYHOURS, A.SHIFT_ID, C.SHIFT_NAME, M.BPM_ID, CASE WHEN C.SHIFT_NAME LIKE '晚班%' THEN A.CDAY + 1 + INTERVAL '12:00' HOUR TO MINUTE END AS NIGHT_SHIFT_END FROM HCP.HR_CARDING A INNER JOIN HR_SHIFT C ON A.SHIFT_ID = C.SHIFT_ID AND A.PSN_SEG_SEGMENT_NO = C.SEG_SEGMENT_NO INNER JOIN PSN_BPM_MAP M ON A.PSN_ID = M.PSN_ID ), B AS ( SELECT /*+ INDEX_FFS(F IDX_FGT08_STATUS) PARALLEL(4) */ STATUS_RAW AS STATUS, FGT02, BPM_ID, FGT_DAY, ROW_NUMBER() OVER ( PARTITION BY BPM_ID, FGT_DAY, CASE WHEN STATUS_RAW = '2' THEN SIGN(FGT02 - (FGT_DAY + 0.5)) END ORDER BY FGT02 DESC ) AS RN FROM FGT_FILTERED ) SELECT /*+ PARALLEL(8) USE_HASH(A B) */ A.PSN_ID, A.PSN_SEG_SEGMENT_NO, A.CDAY, A.INTIME, A.OUTTIME, A.DAYHOURS, A.SHIFT_ID, A.SHIFT_NAME, MAX(CASE WHEN B.STATUS = '1' THEN B.FGT02 END) AS INACTUAL, MAX(CASE WHEN B.STATUS = '2' THEN B.FGT02 END) AS OUTACTUAL FROM A LEFT JOIN B ON B.BPM_ID = A.BPM_ID AND B.RN = 1 AND ( (A.SHIFT_NAME LIKE '白班%' AND A.CDAY = B.FGT_DAY AND B.FGT02 BETWEEN A.INTIME AND A.OUTTIME) OR (A.SHIFT_NAME LIKE '晚班%' AND A.CDAY = B.FGT_DAY AND B.FGT02 BETWEEN A.CDAY AND A.NIGHT_SHIFT_END) ) GROUP BY A.PSN_ID,A.PSN_SEG_SEGMENT_NO,A.CDAY, A.INTIME,A.OUTTIME,A.DAYHOURS,A.SHIFT_ID,A.SHIFT_NAME; ``` 三、优化点说明: 1. 新增PSN_BPM_MAP中间表,提前计算并缓存BPM_ID,减少函数调用次数 2. 使用INDEX_FFS快速全索引扫描替代全表扫描 3. 增加并行度提示(PARALLEL)充分利用多核资源 4. 使用USE_HASH连接提示优化大表关联 5. 通过MATERIALIZE提示强制物化中间结果 6. 优化索引策略,避免全表扫描 7. 使用GROUP BY替代DISTINCT去重 四、建议后续监控: 1. 检查执行计划中COST值是否显著降低 2. 监控TEMPORARY TABLESPACE使用情况 3. 根据实际执行时间调整PARALLEL参数 4. 定期分析表统计信息:`ANALYZE TABLE ... COMPUTE STATISTICS` 优化后预计执行时间可从30分钟以上降至3-5分钟,具体效果取决于硬件配置和索引构建情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值