2013-07-01 228 views
1

有人可以帮我优化我的SQL查询。数据库是postgres。我的表结构如下:SQL查询优化

create table test_table(test_id integer NOT NULL, sequence_id integer NOT NULL,value1 integer NOT NULL, value2 integer NOT NULL, CONSTRAINT test_table_pk PRIMARY KEY (test_id , sequence_id)) 

create table test_event(event_id integer NOT NULL,test_id integer NOT NULL, sequence_id integer NOT NULL , CONSTRAINT test_event_pk PRIMARY KEY(event_id , test_id, sequence_id)) 

test_table 
1,1, 200,300 
2,2, 400,500 
2,3, 600,700 
2,4, 300,500 
2,5, 200,900 

test_event 
1, 1,1 
1, 2,2 
1, 2,3 
2, 2,4 
2, 2,5 

,我想所有的值1和值2,从TEST_TABLE其中sequence_id并为test_id对应于test_event于EVENT_ID = 1。 我的查询看起来像

SELECT 
    value1, value2 
FROM 
    test_table 
WHERE 
    sequence_id IN (
    SELECT sequence_id 
    FROM test_event 
    WHERE event_id=1) AND 
    test_id IN (
    SELECT test_id 
    FROM test_event 
    WHERE event_id=1) 

有人可以请让我知道这是写这个查询的最佳方式?

+0

'EXPLAIN ANALYSE SELECT ...'如果您想知道查询优化器真正想的是什么,请使用真实数据。如果您想知道查询优化器伪造的内容,请使用伪造数据。 –

回答

3

您可以使用INNER JOIN来优化您的查询,这样您就不必在两次不同的属性上查询'test_event'表。

SELECT t.value1, t.value2 
FROM test_table t, test_event e 
WHERE e.event_id = 1 
    AND t.test_id = e.test_id 
    AND t.sequence_id = e.sequence_id 

编辑:添加在评论中提供的建议。

SELECT t.value1, t.value2 
FROM test_table t INNER JOIN test_event e 
ON (e.event_id = 1 
    AND t.test_id = e.test_id 
    AND t.sequence_id = e.sequence_id) 
+0

是的,编写联接可能会产生更优化的查询。但是,请不要使用implict-join(逗号分隔的'FROM'子句),因为它在大多数dbs上被推荐使用,或者完全不推荐使用。它还使得处理像LEFT JOIN这样的事情变得困难 - 最好明确地限定你的连接。另外,请学会格式化查询,以便阅读。 –

+0

如果您认为SQL引擎不会优化查询,那么情况就更糟了:'test_event'上的两个查询将针对'test_table'中的每一行执行。 – contradictioned

+0

@contradictioned - 是的,但这是一个非常愚蠢的优化器,无法将这些查询转换成至少一个临时表键的查找,而聪明的优化器实际上可能会将它变成等同于实际的“JOIN ''查询。 –

1

的问题是,是否sequence_idtest_id必须来自同一个纪录test_event。例如,对(1,2)满足原始查询,因为偶数id 1序列id 2都在具有event_id = 1的行上,但它们不在同一行上。

您的in查询也许是表达这种关系的最佳方式。另一种方法是使用join和聚集:

SELECT tt.value1, tt.value2 
FROM test_table tt join 
    test_event te 
    on te.event_id = 1 
group by tt.value1, tt.value2 
having sum(case when tt.sequence_id = te.sequence_id then 1 else 0 end) > 0 and 
     sum(case when tt.event_id = t2.event_id then 1 else 0 end) > 0; 

这取代了injoin(基本上是交叉连接)和aggregation。我猜想用te.sequence_idte.event_id上的索引,你的原始版本会更好。