![](/img/trans.png)
[英]“Join” between two tables is very fast versus “Left join” which is extremely slow (MySQL DB)
[英]Postgres Left join between two identical tables very slow
嗨,我在理解性能問題時遇到了麻煩。 我有兩個相同的結構化表sensor_values和sensor_values_cleaned結構為
CREATE TABLE sensor_values
(
ts timestamp with time zone NOT NULL,
value double precision NOT NULL DEFAULT 'NaN'::real,
sensor_id integer NOT NULL,
CONSTRAINT sensor_values_sensor_id_fkey FOREIGN KEY (sensor_id)
REFERENCES sensors (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT timestamp_sensor_index UNIQUE (ts, sensor_id)
)
兩個表的ts和sensor_id字段都有索引。 (這些表實際上是按年季度划分的許多分區表)
問題查詢是
SELECT MIN(s1.ts)::timestamptz(0) AS min_time, AVG(s1.value), AVG(s2.value)
FROM sensor_values s1 LEFT JOIN sensor_values_cleaned s2 USING (sensor_id,ts)
WHERE s1.ts::timestamptz >= '2011-02-25T20:25:07.192132+00:00'::timestamptz AND s1.ts::timestamptz <= '2012-12-31T23:59:59.999999'::timestamp
AND s1.sensor_id IN (904 ) GROUP BY s1.ts::timestamptz ORDER BY 1 DESC
這個想法是獲取每個sensor_id的原始數據和清除的數據。 我的原始查詢針對此數據進行了樞軸處理,但由於該部分運行緩慢,因此已將其刪除。
sensor_id 904 has 88000 rows in sensor_values and 0 in sensor_values_cleaned
多次運行后,此查詢大約需要1300毫秒。 問題是當我添加到IN子句時
即
SELECT MIN(s1.ts)::timestamptz(0) AS min_time, AVG(s1.value), AVG(s2.value)
FROM sensor_values s1 LEFT JOIN sensor_values_cleaned s2 USING (sensor_id,ts)
WHERE s1.ts::timestamptz >= '2011-02-25T20:25:07.192132+00:00'::timestamptz AND s1.ts::timestamptz <= '2012-12-31T23:59:59.999999'::timestamp
AND s1.sensor_id IN (904, 967 ) GROUP BY s1.ts::timestamptz ORDER BY 1 DESC
緩存需要15秒。 第一次運行需要40個!
sensor id 967 has 69600 rows in sensor_values and 0 in sensor_values_cleaned.
我已經進行了真空分析
有人知道這個問題或有建議嗎?
謝謝
我的查詢分析在
https://dl.dropboxusercontent.com/u/189370/query_analyze.txt
在以下情況下的最后一個強制轉換( ::timestamp
)可能剝奪了計划者限制表搜索的機會。
WHERE
s1.ts::timestamptz >= '2011-02-25T20:25:07.192132+00:00'::timestamptz AND
s1.ts::timestamptz <= '2012-12-31T23:59:59.999999'::timestamp
嘗試將其更改為
s1.ts >= '2011-02-25t20:25:07.192132+00:00'::timestamptz and
s1.ts < '2013-01-01'::timestamptz
然后比較並發布新計划。 同樣也不需要ts
因為它已經是timestamp with time zone
這不能解釋行為,但可以使其更快:
select
sensor_id,
min(ts)::timestamptz(0) as min_time,
avg(s1.value),
avg(s2.value)
from
(
select ts, "value", sensor_id
from sensor_values
where
ts >= '2011-02-25t20:25:07.192132+00:00'::timestamptz and ts < '2013-01-01'::timestamptz
and sensor_id in (904)
) s1
left join (
select ts, "value", sensor_id
from sensor_values_cleaned
where
ts >= '2011-02-25t20:25:07.192132+00:00'::timestamptz and ts < '2013-01-01'::timestamptz
and sensor_id in (904)
) s2 using (sensor_id,ts)
group by sensor_id
order by 1 desc
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.