Postgresql
如何提高大銷售表中不同供應商的查詢性能?
我有兩張表,一張有儲存數據:
Table "public.store" Column | Type | Modifiers -----------+------------------------+----------- id | integer | not null hul_code | character varying | latitude | numeric | longitude | numeric | name | character varying(100) | Indexes: "store_pkey" PRIMARY KEY, btree (id) "store-hlcode-idx" btree (hul_code)
另一個帶有銷售數據:
Table "public.sale_data" Column | Type | Modifiers -----------+-------------------+----------- id | integer | not null hul_code | character varying | partyname | character varying | rscode | character varying | rsname | character varying | cluster | character varying | channel | character varying | basepack | character varying | total_16 | numeric | total_17 | numeric | total_18 | numeric | Indexes: "sale_data_pkey" PRIMARY KEY, btree (id) "hul-code-idx" btree (hul_code) "sd-bp-idx" btree (basepack) "sd-rscd-idx" btree (rscode)
第二個表有超過 1100 萬行。
我正在嘗試使用以下查詢獲取所有商店的列表,這些商店的商品來自特定區域供應商(由 標識
rscode
):Select s.hul_code, s.name, s.latitude, s.longitude from store s Where hul_code in (Select Distinct(hul_code) as hulcode from sale_data where rscode='133955') AND s.latitude is not null;
此查詢平均需要 1.5 到 2 秒以上。
如何提高這個查詢的速度?
對於典型的數據分佈,模擬鬆散的索引掃描應該是你的魔術。
需要多列索引才能快速:
CREATE INDEX ON sale_data(rscode, hul_code);
對於簡單的情況,在 rCTE 中具有相關子查詢的變體應該是最快的:
WITH RECURSIVE cte AS ( SELECT min(hul_code) AS hul_code FROM sale_data WHERE rscode = '133955' -- provide rscode here UNION ALL SELECT (SELECT hul_code FROM sale_data WHERE rscode = '133955' -- repeat rscode here AND hul_code > c.hul_code ORDER BY 1 LIMIT 1 ) FROM cte c ) SELECT s.hul_code, s.name, s.latitude, s.longitude FROM cte c JOIN store s USING (hul_code);
詳細解釋:
對於特定的數據分佈,可能有更快的替代方案。
旁白:
DISTINCT
(rscode, hul_code)
對於每個不同的行很少(產生大量結果行)的數據分佈可能有意義。但是你所擁有的並沒有多大意義:IN (Select Distinct(hul_code) as hulcode ... )
列別名 (
as hulcode
) 是噪音,因為IN
忽略了列名。
DISTINCT
不需要括號。(hul_code)
被解釋為 ROW 建構子,是ROW(hul_code)
. 在這種情況下,行包裝器恰好會為單列自動剝離。但是您可能會為具有多列的情況引入複雜性。有
DISTINCT ON ()
需要括號的 Postgres 變體,但這裡沒有使用(也不需要)。有關的:但是對於一個
IN
你可能完全放棄的構造,這一切都沒有多大意義DISTINCT
。更好的是,重寫為:SELECT s.hul_code, s.name, s.latitude, s.longitude FROM ( SELECT DISTINCT hul_code FROM sale_data WHERE rscode='133955' ) sd JOIN store s USING (hul_code);
..在不太可能的情況下,您應該有這樣的數據分佈。
而且您的列
rscode
似乎包含數字數據。如果是這樣,它應該是數字類型,而不是varchar
.