SELECT MAX(verification_id)
FROM VERIFICATION_TABLE
WHERE head = 687422
AND mbr = 23102
AND RTRIM(LTRIM(lname)) = '.iq bzw'
AND TO_CHAR(dob,'MM/DD/YYYY')= '08/10/2004'
AND system_code = 'M';
此查询需要153秒才能运行。 VERIFICATION_TABLE
中有数百万行。
我认为由于where子句中的函数,查询需要很长时间。但是,我需要在列上执行ltrim rtrim,并且日期必须以MM/DD/YYYY
格式匹配。如何优化此查询?
解释计划:
SELECT STATEMENT, GOAL = ALL_ROWS 80604 1 59
SORT AGGREGATE 1 59
TABLE ACCESS FULL P181 VERIFICATION_TABLE 80604 1 59
主键:
VRFTN_PK Primary VERIFICATION_ID
索引:
N_VRFTN_IDX2 head, mbr, dob, lname, verification_id
N_VRFTN_IDX3 last_update_date
N_VRFTN_IDX4 mbr, lname, dob, verification_id
N_VRFTN_IDX4 verification_id
虽然在解释计划中我没有看到使用索引/主键。那是问题吗?
答案 0 :(得分:3)
试试这个:
SELECT MAX(verification_id)
FROM VERIFICATION_TABLE
WHERE head = 687422
AND mbr = 23102
AND TRIM(lname) = '.iq bzw'
AND TRUNCATE(dob) = TO_DATE('08/10/2004')
AND system_code = 'M';
如果TRUNCATE()
已经有dob
已经没有时间,那么请删除mbr
,从它的外观(出生日期?)可能不会。过去,你需要一些索引工作。如果您以这种方式查询那么多,我会在2列索引中对head
和{{1}}进行索引,如果您说明了这些列的含义,那么它将有助于确定最佳索引。< / p>
答案 1 :(得分:2)
唯一可能在查询中使用的索引是N_VRFTN_IDX2,因为它索引了WHERE子句中使用的四个列:HEAD,MBR,DOB和LNAME。
但是,因为您将功能应用于DOB和LNAME,所以它们没有资格考虑。然后优化器可以决定不使用该索引,因为它认为HEAD + MBR本身是不充分选择性的组合。如果从DOB中删除了TO_CHAR()调用,则N_VRFTN_IDX2上有三个前导列,这可能使其对优化器更具吸引力。同样,是否有必要TRIM()LNAME?
另一方面,需要查找SYSTEM_CODE意味着查询必须从表中读取(因为该列未被索引)。如果N_VRFTN_IDX2具有较差的聚类因子,则优化器可能决定进行FULL TABLE SCAN,因为索引读取是开销。然而,如果您将SYSTEM_CODE添加到索引中,则可以通过INDEX RANGE SCAN满足整个查询,这将快得多。
最后,您的统计数据有多新鲜?如果您的统计信息过时,可能会导致优化程序做出决定。例如,更准确的统计信息可能会导致优化器使用复合索引,即使只有两个前导列。
答案 2 :(得分:1)
您应该将文字转换为DATE,而不是将列转换为VARCHAR2,如下所示:
AND dob = TO_DATE('08/10/2004','MM/DD/YYYY')
或者使用首选的ANSI日期文字语法:
AND dob = DATE '2004-08-10'
如果dob栏包含时间(通常不是出生日期,可能在医院除外!)那么你可以这样做:
AND dob >= DATE '2004-08-10'
AND dob < DATE '2004-08-11'
答案 3 :(得分:1)
检查HEAD和MBR的数据类型。 值“687422和23102”具有非常有选择性的“感觉”。也就是说,如果表中有数十万个head和数百万条记录的值,那么看起来HEAD是非常有选择性的。 [虽然这可能完全是误导。]
无论如何,您可能会发现HEAD和/或MBR实际上存储为VARCHAR2或CHAR字段而不是NUMBER。如果是这样,将字符与数字进行比较将阻止使用索引。尝试以下(我已经将dob谓词转换为日期,但添加了显式格式掩码)。
SELECT MAX(verification_id)
FROM VERIFICATION_TABLE
WHERE head = '687422'
AND mbr = '23102'
AND RTRIM(LTRIM(lname)) = '.iq bzw'
AND TRUNCATE(dob) = TO_DATE('08/10/2004','MM/DD/YYYY')
AND system_code = 'M';
答案 4 :(得分:0)
请在此查询中提供EXPLAIN输出,以便我们知道减速发生的位置。两个想法:
更改
AND TO_CHAR(dob,'MM/DD/YYYY')= '08/10/2004'
到
AND dob = <date here, not sure which oracle str2date function you need>
并使用基于函数的索引
RTRIM(LTRIM(lname))
答案 5 :(得分:0)
试试这个:
SELECT MAX(verification_id)
FROM VERIFICATION_TABLE
WHERE head = 687422
AND mbr = 23102
AND TRIM(lname) = '.iq bzw'
AND dob between TO_DATE('08/10/2004') and TO_DATE('08/11/2004')
AND system_code = 'M';
这样就可以使用dob的可能索引。