2014-05-09 75 views
0

我有下面表的Oracle 11g樞軸查詢優化 - 多行單列

user table 
USER_ID USER_NAME 
1   smith 
2   clark 
3   scott 
4   chris 
5   john 

property table 
P_ID PROPERTY 
1  first_name 
2  last_name 
3  age 
4  skill 

user_property table 
PV_ID USER_ID P_ID VALUE 
1  1   1 Smith 
2  1   2 A 
3  1   3 34 
4  1   4 Java 
5  1   4 DB 
6  2   1 Clark 
7  2   2 B 
8  2   3 39 
9  2   4 Java 
10  2   4 net 
11  2   4 linux 
12  3   1 Scott 
13  3   2 C 
14  3   3 31 

我想要寫一個查詢將從如下所有上述各表獲取數據:(技巧將是該第一個技能用戶如果可用,否則無效)

USER_ID USER_NAME FIRST_NAME LAST_NAME SKILL 
1  smith  Smith  A   Java 
2  clark  Clark  B   Java 
3  scott  Scott  C   null 

我試圖像下面,但得到的性能問題:

SELECT 
    u.user_id, 
    u.user_name, 
    MAX(DECODE(p.property, 'first_name', text_value)) firstName, 
    MAX(DECODE(p.property, 'last_name', text_value)) lastName, 
    MAX(DECODE(p.property, 'age', text_value)) age, 
    MAX(DECODE(p.property, 'skill', text_value)) skill 
FROM user u, 
    property p, 
    user_property up, 
WHERE u.user_id = up.user_id 
AND p.p_id = up.p_id 
GROUP BY u.user_id, 
    u.user_name; 

我怎麼能寫這個作爲oracle 11g的優化查詢。

+0

那麼你在每個表中有多少行? – Mihai

回答

0

查詢的性能取決於表的大小以及這些表上的索引。大多數情況下,對每個主鍵和外鍵都有一個索引是最好的做法。無論如何,主鍵上的索引是必須的。當您刪除行時,外鍵上的索引加速聯接並阻止表鎖。

到您的查詢另一種方法是使用更多的聯接,而不是子查詢和使用WITH子句簡化它:BTW

with t as (
    select u.user_id, u.user_name, up.p_id, up.value 
    from user_property up 
    join user u on u.user_id = up.user_id 
) 
select u.user_id, u.user_name, 
    t_first_name.value first_name, 
    t_last_name.value last_name, 
    (select min(value) from t where t.user_id = u.user_id and t.p_id = 4) skill 
from user u 
left join t t_first_name on t_first_name.user_id = u.user_id and t_first_name.p_id = 1 
left join t t_last_name on t_last_name.user_id = u.user_id and t_last_name.p_id = 2; 

:這是一個數據模型,它不適合於SQL。我希望這些用戶屬性是個例外,其餘的數據庫都有一個更清晰的設計。

+0

屬性表有286條記錄,用戶表有115838條記錄,user_property有3221472條記錄。所有表格都有PK上的索引。 – KNale

+0

**屬性表有286條記錄**(對此我們感興趣的是大約45個屬性,意味着輸出select子句中有45列),用戶表有115838條記錄,user_property有3221472條記錄。所有表格都有PK上的索引。由於我們有大約45列,最小/最大值可能會影響性能 – KNale

+0

您是否希望最終輸出爲每個115,838個用戶添加一行?或者你對一部分用戶感興趣? – Torino

0

我試過下面的查詢卻得到笛卡爾積。

with t as (
select u.user_id, u.user_name, up.p_id, up.value 
from user_property up 
join user u on u.user_id = up.user_id 
where u.user_name = 'smith' 
) 
select u.user_id, u.user_name, 
t_first_name.value first_name, 
t_last_name.value last_name, 
(select min(value) from t where t.user_id = u.user_id and t.p_id = 4) skill 
from user u 
left join t t_first_name on t_first_name.user_id = u.user_id and t_first_name.p_id = 1 
left join t t_last_name on t_last_name.user_id = u.user_id and t_last_name.p_id = 2; 

如果我執行以下查詢我得到5如在我的上述示例中提到的(由於有5行我user_property表USER_ID 1的示例中)

select count(u.user_id) 
from user_property up 
join user u on u.user_id = up.user_id 
where u.user_name = 'smith' 

因此,如果我執行下面的查詢我的計數爲3,因爲在我的使用表中有3行示例

with t as (
select u.user_id, u.user_name, up.p_id, up.value 
from user_property up 
join user u on u.user_id = up.user_id 
where u.user_name = 'smith' 
) 
select count(u.user_id) 
from user u 
left join t t_first_name on t_first_name.user_id = u.user_id and t_first_name.p_id = 1 
left join t t_last_name on t_last_name.user_id = u.user_id and t_last_name.p_id = 2; 
+0

爲什麼你添加這個作爲答案,而不是更新你的原始問題?編輯自己的問題是否需要最低限度的聲譽? – Torino

+0

我不明白你爲什麼得到笛卡爾產品。我的查詢是正確的:看到[小提琴](http://sqlfiddle.com/#!4/b3495e/3)。 – Torino

+0

@Torino:感謝您的更新。其工作工作。 Howerver原始查詢需要145秒,這個新查詢需要130秒才能執行。 – KNale