Oracle数据库。
我有以下一段SQL对PROVIDER P1表执行全表扫描。我相信这是因为它正在动态建立一个like子句,就像您在XXX行看到的一样。
我在PROVIDER.TERMINAL_NUMBER上有一个索引,并且以下SQL代码段确实使用了正确的索引。
select * from providers where terminal_number like '1234%'
那么为什么以下内容没有达到该索引?
SELECT P1.PROVIDER_NUMBER, P1.TERMINAL_NUMBER, PC."ORDER" FROM PROVIDERS P1
INNER JOIN PROVIDER_CONFIG PC
ON PC.PROVIDER_NUMBER = P1.PROVIDER_NUMBER
WHERE EXISTS (
SELECT E2.* FROM EQUIPMENT E1
INNER JOIN EQUIPMENT E2
ON E1.MERCHANT_NUMBER = E2.MERCHANT_NUMBER
WHERE E1.TERMINAL_NUMBER = 'SA323F'
AND E1.STATUS IN (0, 9)
AND E2.STATUS IN (0, 9)
XXX
AND P1.TERMINAL_NUMBER LIKE SUBSTR(E2.TERMINAL_NUMBER, 0, length(E2.TERMINAL_NUMBER) - 1) || '%'
)
ORDER BY PC."ORDER" DESC
答案 0 :(得分:1)
这里...
select * from providers where terminal_number like '1234%'
...优化器知道所有配件编号均以固定前缀开头,因此将被共置在索引中。因此,读取索引可能非常有效。
但是这里没有这样的知识...
P1.TERMINAL_NUMBER LIKE SUBSTR(E2.TERMINAL_NUMBER, 0, length(E2.TERMINAL_NUMBER) - 1) || '%'
E2.TERMINAL_NUMBER
中可以有许多不同的前缀,并且查询将返回PROVIDERS
表中所有记录。因此,索引读取的效率将非常低,采用完全钝化的全扫描方法是正确的选择。
可能可以重写查询,使其更有效地工作-例如,您需要快速全索引扫描而不是全表扫描。但是,在不知道您的数据和业务规则的情况下,我们实际上无法提供帮助,尤其是在涉及动态查询生成时。
可能会提高性能的一件事是将WHERE EXISTS替换为WHERE IN ...
SELECT P1.PROVIDER_NUMBER, P1.TERMINAL_NUMBER, PC."ORDER" FROM PROVIDERS P1
INNER JOIN PROVIDER_CONFIG PC
ON PC.PROVIDER_NUMBER = P1.PROVIDER_NUMBER
WHERE substr(P1.TERMINAL_NUMBER, 1, 5) IN (
SELECT SUBSTR(E2.TERMINAL_NUMBER, 1, 5)
FROM EQUIPMENT E1
INNER JOIN EQUIPMENT E2
ON E1.MERCHANT_NUMBER = E2.MERCHANT_NUMBER
WHERE E1.TERMINAL_NUMBER = 'SA323F'
AND E1.STATUS IN (0, 9)
AND E2.STATUS IN (0, 9)
)
ORDER BY PC."ORDER" DESC
如果终端号码的长度是恒定的,这将起作用。只有您知道您的数据,因此只有您可以知道它是否会飞行。
答案 1 :(得分:0)
如果此查询不使用索引:
select *
from providers
where terminal_number like '1234%'
然后,terminal_number
可能是数字而不是字符串。类型转换会阻止使用索引。
如果要使用索引,则将值转换为字符串并使用字符串索引:
create index idx_providers_terminal_number_str on providers(cast(terminal_number as varchar2(255)));
然后将查询写为:
select *
from providers
where cast(terminal_number as varchar2(255)) like '1234%'