2

这是我的查询,

   SELECT ID As Col1,
   (
         SELECT VID FROM TABLE2 t 
         WHERE (a.ID=t.ID or a.ID=t.ID2) 
         AND t.STARTDTE =
         (
               SELECT MAX(tt.STARTDTE) 
               FROM TABLE2 tt 
               WHERE (a.ID=tt.ID or a.ID=tt.ID2)  AND tt.STARTDTE < SYSDATE
         )
   ) As Col2
   FROM TABLE1 a

Table1 有 48850 条记录,Table2 有 15944098 条记录。

我在 TABLE2 中有关于 ID、ID 和 STARTDTE、STARTDTE、ID、ID2 和 STARTDTE 的单独索引。

查询仍然太慢。如何改进?请帮忙。

4

3 回答 3

3

我猜测ORin 内部查询正在破坏优化器使用索引的能力。此外,我不会推荐一种可以扫描所有TABLE2给定大小的解决方案。

这就是为什么在这种情况下,我建议使用一个可以有效检索您正在寻找的信息的函数(每次调用 2 次索引扫描):

CREATE OR REPLACE FUNCTION getvid(p_id table1.id%TYPE) 
   RETURN table2.vid%TYPE IS
   l_result table2.vid%TYPE;
BEGIN
   SELECT vid
     INTO l_result
     FROM (SELECT vid, startdte
             FROM (SELECT vid, startdte
                     FROM table2 t
                    WHERE t.id = p_id
                      AND t.startdte < SYSDATE
                    ORDER BY t.startdte DESC)
            WHERE rownum = 1
           UNION ALL
           SELECT vid, startdte
             FROM (SELECT vid, startdte
                     FROM table2 t
                    WHERE t.id2 = p_id
                      AND t.startdte < SYSDATE
                    ORDER BY t.startdte DESC)
            WHERE rownum = 1
            ORDER BY startdte DESC)
    WHERE rownum = 1;
   RETURN l_result;
END;

您的 SQL 将变为:

SELECT ID As Col1,
       getvid(a.id) vid
  FROM TABLE1 a

table2(id, startdte DESC)确保在和上都有索引table2(id2, startdte DESC)。索引的顺序非常重要。

于 2012-09-25T14:55:59.533 回答
1

可能尝试以下,虽然未经测试。

WITH max_times AS
    (SELECT a.ID, MAX(t.STARTDTE) AS Startdte
     FROM TABLE1 a, TABLE2 t 
     WHERE (a.ID=t.ID OR a.ID=t.ID2) 
         AND t.STARTDTE < SYSDATE
     GROUP BY a.ID)
SELECT b.ID As Col1, tt.VID
FROM TABLE1 b
    LEFT OUTER JOIN max_times mt
    ON (b.ID = mt.ID)
    LEFT OUTER JOIN TABLE2 tt
    ON ((mt.ID=tt.ID OR mt.ID=tt.ID2) 
        AND mt.startdte = tt.startdte)
于 2012-09-25T14:43:41.737 回答
1

您可以查看分析函数以避免不得不两次点击第二个表。像这样的东西可能会起作用:

SELECT id AS col1, vid
FROM (
    SELECT t1.id, t2.vid, RANK() OVER (PARTITION BY t1.id ORDER BY
        CASE WHEN t2.startdte < TRUNC(SYSDATE) THEN t2.startdte ELSE null END
        NULLS LAST) AS rn
    FROM table1 t1
    JOIN table2 t2 ON t2.id IN (t1.ID, t1.ID2)
)
WHERE rn = 1;

内部选择从两个表中获取id和值,并在orvid上进行简单连接。该函数根据 . 计算第二个表中每个匹配行的排名。你想过滤那个日期有点复杂,所以我使用 a通过将评估值更改为 null 来有效地忽略今天或以后的任何日期,在这种情况下,这意味着子句中的忽略。idid2rankstartdtecaseorder byovernulls last

我建议您首先单独运行内部选择 - 可能只是id为了简洁起见,只需几个值 - 看看它在做什么,以及正在分配什么等级。

然后,外部查询只是为 each 选择排名靠前的结果id

不过,您仍然可能会得到重复;如果table2有多个相同的行,id他们startdte将获得相同的排名,但是您之前可能遇到过这种情况。您可能需要以order by对您有意义的方式向 中添加更多字段以打破关系。

但这主要是推测,无法查看您现有查询的实际速度慢的地方。

于 2012-09-25T14:59:45.277 回答