2017-02-13 13 views
10

Postgres tarafından yayınlanan docs/wiki dosyasında işlevsel indeksler ve yalnızca dizin taramaları hakkında bilgi okudum.postgres 9.6 dizin sadece mantıksal olarak mantıksal olarak taranabilir fakat çalıştırılamıyor

SELECT(xpath('/document/uuid/text()', xmldata))[1]::text, 
     (xpath('/document/title/text()', xmldata))[1]::text 
FROM xmltable 
WHERE(xpath('/document/uuid/text()', xmldata))[1]::text = 'some-uuid-xxxx-xxxx' 

ve dizin:

CREATE INDEX idx_covering_index on xmltable using btree (
    ((xpath('/document/uuid/text()', xmldata))[1]::text),  
    ((xpath('/document/title/text()', xmldata))[1]::text) 
) 

Bu indeks, mantıksal olarak bakarak, bir örtü endeksidir ve bir indeks okunur-tarama imkan vermelidir

Ben şimdi gibi bir sorgu var Tüm sorgulanan değerler index (uuid ve başlık)

'da yer aldığından, şimdi biliyoruz ki, Postgres yalnızca fonksiyon indekslerinde kullanılan sütunlar fonksiyon parametrelerinde kullanılıyorsa n-çağrılar da

bulunan örn .:

SELECT to_upper(column1) from table where id >10 

1) bu endeks ile karşılanması mümkün değildir:

CREATE INDEX idx_covering_index on xmltable using btree (id, to_upper(column1)); 

2) ama bu bir tarafından karşılanabilir:

CREATE INDEX idx_covering_index on xmltable using btree (column1, id, to_upper(column1)); 

, yalnızca bir dizin taramasına yol açar. Şimdi benim xml kurulumu ile bu denerseniz

: "xml" kabul etmiyoruz maalesef normalde "text_ops" veya "text_pattern_ops" kullanılan, yeterince

data type xml has no default operator class for access method "btree"

adil:

CREATE INDEX idx_covering_index on xmltable using btree (xmldata, 
    ((xpath('/document/uuid/text()', xmldata))[1]::text),  
    ((xpath('/document/title/text()', xmldata))[1]::text) 
) 

bir hata alıyorum girdi - böylece indeksimi oluşturuyor - tüm değerleri kapsayacak şekilde olsa da - sadece dizin-taramalarını destekleyemiyor.

Bu, yalnızca dizinlere tarama olanağı sağlayan bir şekilde kullanılabilir mi?

Edit1 @:

Ben postgres endeksi kapsayan olarak 1'de görülen endeksi) kullanamazsınız, ama aynı zamanda bu davranışı doğrulamak için çok basit tablolarla denenmiş 2 gibi bir dizin)

kullanabileceğinizi biliyor ve ben de bunu okumayı hatırlıyorum - ama hayatımın için nerede olduğunu hatırlayamıyorum. EDIT2 @

create table test (
    id serial primary key, 
    quote text 
) 



insert into test (number, quote) values ('I do not know any clever quotes'); 
insert into test (number, quote) values ('I am sorry'); 



CREATE INDEX idx_test_functional on test using btree ((regexp_replace(quote, '^I ', 'BillDoor '))); 
set enable_seqscan = off; 

analyze test; 

explain select quote from test where regexp_replace(quote, '^I ', 'BillDoor ') = 'BillDoor do not know any clever quotes' 

--> "Index Scan using idx_test_functional on test (cost=0.13..8.15 rows=1 width=27)" 

drop index idx_test_functional; 
CREATE INDEX idx_test_functional on test using btree (quote, (regexp_replace(quote, '^I ', 'BillDoor '))); 

analyze test; 

explain select quote from test where regexp_replace(quote, '^I ', 'BillDoor ') = 'BillDoor do not know any clever quotes' 

--> "Index Only Scan using idx_test_functional on test (cost=0.13..12.17 rows=1 width=27)" 

: xmltable arasında

Tam tablo tanımı:

id serial primary key (clustered), 
xmldata xml (only data used to filter queries) 
history xml (never queried or read, just kept in case of legal inquiry) 
fileinfo text (seldom quieried, sometimes retrieved) 
"timestamp" timestamp (mainly for legal inquiries too) 

Tablo yaklaşık içerir .: 500.000 Kayıtlar, xmldata boyutu 350 ile 800 bayt arasındadır, tarih çok daha büyüktür ama nadiren alınabilir ve filtrelerde hiç kullanılmaz

Kayıt için, gerçek sonuçlara sahip olabilmek için, her zaman ben oluşturuldum veya bıraktıktan sonra analyze xmltable koştum bir dizin

sorgu için tam bir yürütme planı:

explain analyze select (xpath('/document/uuid/text()', d.xmldata))[1]::text as uuid 
from xmltable as d 
where 
(xpath('/document/uuid/text()', d.xmldata))[1]::text = 'some-uuid-xxxx-xxxx' and (xpath('/document/genre/text()', d.xmldata))[1]::text = 'bio' 

bu indizies kapsadığı:

create index idx_genre on xmltable using btree (((xpath('/document/genre/text()', xmldata))[1]::text)); 

create index idx_uuid on xmltable using btree (((xpath('/document/uuid/text()', xmldata))[1]::text)); 

create index idx_uuid_genre on xmltable using btree (((xpath('/document/uuid/text()', xmldata))[1]::text), ((xpath('/document/genre/text()', xmldata))[1]::text)); 

ilk Lea için DS: - zihnimde -

"Index Scan using idx_genre on xmldata d (cost=0.42..6303.05 rows=18154 width=32)" 
" Index Cond: (((xpath('/document/genre/text()'::text, xmldata, '{}'::text[]))[1])::text = 'bio'::text)" 
" Filter: (((xpath('/document/uuid/text()'::text, xmldata, '{}'::text[]))[1])::text = 'some-uuid-xxxx-xxxx'::text)" 

adil yeterince i kullanmaya zorlamak edeceğiz sadece test için, düşünce kapsayan endeksi:

drop index idx_uuid; 
drop index idx_genre; 

ve şimdi olsun:

"Bitmap Heap Scan on xmltable d (cost=551.13..16025.51 rows=18216 width=32)" 
" Recheck Cond: ((((xpath('/document/genre/text()'::text, xmldata, '{}'::text[]))[1])::text = 'bio'::text) AND (((xpath('/document/uuid/text()'::text, xmldata, '{}'::text[]))[1])::text = 'some-uuid-xxxx-xxxx'::text))" 
" -> Bitmap Index Scan on idx_uuid_genre (cost=0.00..546.58 rows=18216 width=0)" 
"  Index Cond: ((((xpath('/document/genre/text()'::text, xmldata, '{}'::text[]))[1])::text = 'bio'::text) AND (((xpath('/document/uuid/text()'::text, xmldata, '{}'::text[]))[1])::text = 'some-uuid-xxxx-xxxx'::text))" 

Ayrıca, aynı yürütme planı, dizinde uuid ve tür anahtarlama pozisyonları çalıştı.

+0

'Artık biliyoruz ki, postgres yalnızca işlev göstergelerinde kullanılan sütunların işlevlerini de içeren sütunları içeriyorsa işlev göstergelerindeki örtüşen göstergeleri de tanır; bu, bu belgeyi destekleyen belgelere herhangi bir gönderme yapabilir; çok karşı sezgisel. Yani ... nasıl şimdi biliyorsunuz ". –

+0

'xmltable' tablonun tam tanımı nedir? Endeks mevcut ise icra için icra planı nedir? Postgres bir indeks araması için indeksi kullanıyor mu yoksa bu endeksi hiç kullanmıyor mu? –

+0

biliyorum çünkü xml, düzenli tablolar, json vb. Ile denedim ve aynı zamanda bana garip görünüyordu - bu – billdoor

cevap

7

DÜZENLEME FİNAL: o belgelere göre

imkansızdır Neden: endeksi tipi (yani btree her zaman bu destekler bu destek edildiğinde indexonly yapabilirsiniz postgresql tarar sadece bazı belirli operatörler için GiST ve SpGiST ve GIN hiç yetenekli değildir. VE indeksinden orijinal endekslenmiş değeri yeniden oluşturmak mümkündür.

İkinci gereksinim en ilgi çekicidir.

Sütunlarda bu basit (a, b) şeklindedir ve dizininiz orijinal saklanan değeri yeniden oluşturabilir.

Fonksiyonel indeks çalışma fonksiyonlarının yapılması durumunda orijinal değerlere sahip indeks oluşturmalısınız. Bu, (f1(a), f2(b)) dizininin bir kez daha tabloya geleceği anlamına gelir, çünkü bu değerlerden dizine eklenmiş verileri yeniden oluşturamazsınız (a, b). Geliştiriciler tarafından önerilen geçici çözüm, (f1(a), f2(b), a, b) dizinini oluşturmaktır. Bu durumda sorgu planlayıcısı, indeks orijinal verileri içerdiğinden, yalnızca dizin taramasının çalıştırılmasının mümkün olduğunu belirleyebilir.

Sorunuza geri dönersek, yalnızca xml sütunu üzerinde dizin oluşturma imkansızdır: btree için çok önemli olan xml veri karşılaştırmasını destekleyen hiçbir operatör yoktur. Xml verileri için karşılaştırma operatörleri tanımı yoktur. Bu nedenle, bu sütunu herhangi bir dizinde kullanamazsınız, ancak yalnızca dizin taraması yapmanıza gerek duyarsınız, yalnızca dizin taraması gerçekleştirmek için sorgu iyileştiricisine ipucu verin.

DÜZENLEME: O veri sık kullanılan olacağını biliyorsanız

(indeks-yalnızca belirli xpath ifadeleri üzerine tarama nasıl elde çözeltisi), ben tetik fonksiyonu ve 2 oluşturarak yoluyla bu sorunu çözmek için öneriyoruz daha fazla alan ve bunları indeksle doldurun.Bunun gibi bir şey:

ALTER TABLE public.xmltable ADD COLUMN xpath_uuid character varying(36); 
ALTER TABLE public.xmltable ADD COLUMN xpath_title character varying(100); 


CREATE INDEX idx_covering_materialized_xml_data 
    ON public.xmltable 
    USING btree 
    (xpath_uuid COLLATE pg_catalog."default", xpath_title COLLATE pg_catalog."default"); 

CREATE OR REPLACE FUNCTION public.introduce_xml_materialization() 
    RETURNS trigger AS 
$BODY$BEGIN 

NEW.xpath_uuid = (xpath('/document/uuid/text()', NEW.xmldata))[1]::text; 
NEW.xpath_title = (xpath('/document/title/text()', NEW.xmldata))[1]::text; 

RETURN NEW; 
END;$BODY$ 
    LANGUAGE plpgsql STABLE 
    COST 100; 



CREATE TRIGGER index_xml_data 
    BEFORE INSERT OR UPDATE 
    ON public.xmltable 
    FOR EACH ROW 
    EXECUTE PROCEDURE public.introduce_xml_materialization(); 

ve sonra basitçe yapabilirsiniz:

SELECT xpath_uuid, xpath_title 
    FROM public.xmltable 
    where xpath_uuid = ' uuid1 ' 

size gösterecektir endeks salt tarayın:

"Index Only Scan using idx_covering_materialized_xml_data on xmltable (cost=0.14..8.16 rows=1 width=308)" 
" Index Cond: (xpath_uuid = ' uuid1 '::text)" 

Bu yaklaşım, optimum olmasını verileri varsayarak ediyorum yazılandan daha fazla okunur. Ekleme veya güncelleme maliyetinden genellikle xpath ifadelerinde fonksiyonel indeks oluşturma ile aynıdır.

ORİJİNAL TEPKİ: Eh sorun sorgu iyileştirici xPath işlev çağrısı basit olduğunu düşünüyor olmasıdır

(sorgu en iyi duruma çimdik isteyenler için ilginç olabilir). yani basit matematik operatörünü çağırmak gibidir ve maliyeti 1'dir. Bu durumda sorgu iyileştiricisi, tablodan almanın ve bir kez daha hesaplamanın daha kolay olduğunu, sonra sadece saf indeks taramasının yapıldığını düşünür.

Xpath çağrı maliyetini artırırsanız, 1000'i sorgu eniyileyicisinin, böyle bir çağrının (aslında doğru olan) bu tür çağrının çok daha zor olduğunu görecek ve yalnızca dizin taraması yapmaya çalışacağını göreceksiniz. benim test kurulumunda ben

update pg_proc set procost=1 where proname='xpath'; 

infaz ettiniz ve yürütme planı

"Bitmap Heap Scan on xmltable (cost=4.17..11.30 rows=3 width=64)" 
" Recheck Cond: (((xpath('/document/uuid/text()'::text, xmldata, '{}'::text[]))[1])::text = 'some-uuid-xxxx-xxxx'::text)" 
" -> Bitmap Index Scan on idx_covering_index_3 (cost=0.00..4.17 rows=3 width=0)" 
"  Index Cond: (((xpath('/document/uuid/text()'::text, xmldata, '{}'::text[]))[1])::text = 'some-uuid-xxxx-xxxx'::text)" 

olduğu Ama

update pg_proc set procost=1000 where proname='xpath'; 

Yürütme planı geçiş yapmak zaman indeksi okunur

"Index Scan using idx_covering_index_3 on xmltable (cost=0.15..31.20 rows=3 width=64)" 
" Index Cond: (((xpath('/document/uuid/text()'::text, xmldata, '{}'::text[]))[1])::text = 'some-uuid-xxxx-xxxx'::text)" 
taramak

Ve hacmimde (örneğin; hiçbir veri) indeks sadece sorgu minimum maliyet orijinal indeks + tablo tarama, howerver maksimum maliyet daha büyüktür daha önemli. Böylece, sorgu optimizasyonunu almanız için xpath çağrı maliyetine daha yüksek değerler koymanız gerekebilir.

Umarım bu yardımcı olur, Ve meraktan dolayı, sadece indeksle sorgulamayı kullanma kazançlarını bize göster.

+0

sorgu planıyla ilgili olduğunu hatırlıyorum. Yalnızca Dizin Taramasına değil, Dizin Taramasına - belki bir yanlış anlama mı? – billdoor

+0

sadece bir göz atın: İlk sorgu (xPath maliyeti 1 olduğunda) indeks üzerinden çalışıyor (idx_covering_index_3 üzerinde Bitmap İndeks Taraması) ve daha sonra tablodan veri alır (xmltable'da Bitmap Heap Scan). İkinci sorgu (xPath maliyeti 100 olduğunda) sadece dizin (idx_covering_index_3 kullanarak Index Scan) üzerinden çalışır ve tabloyu tarar. –

+0

Tam olarak istediğin şey bu değil (* Yalnızca Dizini Tara *), ancak bu oldukça iyi bir gelişme olabilir. O zaman ben oy vereceğim. –

İlgili konular