重写 NOT IN,但子查询涉及逗号分隔的字符串 (ID)
Posted
技术标签:
【中文标题】重写 NOT IN,但子查询涉及逗号分隔的字符串 (ID)【英文标题】:Rewrite NOT IN, but subquery involves a comma seperated string (ID) 【发布时间】:2017-07-28 10:58:34 【问题描述】:使用 SQL Developer 更改 Oracle 存储过程。
输入:逗号分隔的 ID。 (例如:'P23,P37,P39,P45') 编辑:请注意输入是一个字符串,不是一个字符串数组。此外,字符串可能不仅仅是 4 个 ID。最高可达 200 左右。
想从没有那些输入 ID 的表中找出。
以下太慢了。大约 300 行数据(在表中)但大约需要 20 秒。所以我想重写。请给我一些关于如何做的提示。
ID_Array 是 'P23,P37,P39,P45'。
SELECT * FROM StudentInfo
WHERE StudentClass = 'Primary5A'
AND StudentID NOT IN
(
SELECT REGEXP_SUBSTR(ID_Array, '[^,]+', 1, LEVEL) StudentID
FROM DUAL
CONNECT BY REGEXP_SUBSTR(ID_Array, '[^,]+', 1, LEVEL) IS NOT NULL
)
AND Height <= 150;
你们中的一些人可能已经知道了。以下
SELECT REGEXP_SUBSTR(ID_Array, '[^,]+', 1, LEVEL) StudentID
FROM DUAL
CONNECT BY REGEXP_SUBSTR(ID_Array, '[^,]+', 1, LEVEL) IS NOT NULL
会将 ID_Array 变成一个有四行的表(类似表的结构?):
+-----+
| P23 |
| P37 |
| P39 |
| P45 |
+-----+
【问题讨论】:
硬编码需要多长时间:AND StudentID NOT IN ('P23','P37','P39','P45') AND Height <= 150
?两者的执行计划是什么?您的统计数据是最新的吗?
当您操作的是字符串而不是表格时,拆分逗号分隔字符串的各种方法之间几乎没有区别。我认为 Alex 建议的还有其他问题。
我对字符串进行了硬编码。执行计划:基数:184,成本:191,使用 real 数据。它对 StudentInfo 进行了全表扫描。使用下面的答案,两个执行计划都非常低(例如成本:5)。
【参考方案1】:
您的 ID_Array 必须比此处的示例长很多。 'P23,P37,P39,P45' 的表现非常好。
如果字符串较长,REGEXP_SUBSTR
会变得非常慢。我建议尽可能使用LIKE
,即使它变得很奇怪。试试这个。
SELECT * FROM StudentInfo
WHERE StudentClass = 'Primary5A'
AND ','||ID_Array||',' NOT LIKE '%,'||StudentID||',%'
AND Height <= 150;
【讨论】:
是的,ID_Array 更长。花费的时间比大卫的答案要少一些,所以我“勾选”你的答案是公认的答案。谢谢。【参考方案2】:即使您使用的是正则表达式,也无需使用CONNECT BY
。您可以使用LIKE
,也可以使用REGEXP_LIKE()
:
SELECT * FROM studentinfo
WHERE studentclass = 'Primary5A'
AND height <= 150
AND NOT REGEXP_LIKE(','||id_array||',', ','||studentid||',');
我猜id_array
不够短,不能用作正则表达式模式本身(300 行?)。如果是,您可以执行以下操作:
SELECT * FROM studentinfo
WHERE studentclass = 'Primary5A'
AND height <= 150
AND NOT REGEXP_LIKE(student_id, '^(' || REPLACE(id_array, ',', '|') || ')$');
但我认为,Oracle 中的正则表达式模式限制为 512 个字节。
【讨论】:
我实际上让第一个工作代替。第二个抱怨正则表达式太长。感谢您的帮助。 是的,Oracle 正则表达式限制为 512 个字节以上是关于重写 NOT IN,但子查询涉及逗号分隔的字符串 (ID)的主要内容,如果未能解决你的问题,请参考以下文章
重写 Equals 方法时是不是需要重写 == 和 != 运算符? (。网)
shiro-重写标签功能----shiro:hasPermission 标签重写