Tüm Ürünler
Search
Belge Merkezi

Hologres:EXPLAIN and EXPLAIN ANALYZE

Son Güncelleme:Oct 06, 2026

Hologres'in bir SQL sorgusunu nasıl çalıştırdığını incelemek için EXPLAIN ve EXPLAIN ANALYZE komutlarını kullanın. Bir sorgu kötü performans gösterdiğinde veya beklenmeyen sonuçlar döndürdüğünde, bu komutlar yürütme planını gösterir; böylece darboğazları belirleyebilir ve SQL veya tablo tasarımınızı optimize edebilirsiniz.

Hologres V1.3.4x ve sonraki sürümlerdeki yürütme planları daha net ve okunabilirdir. Bu belge V1.3.4x tabanlıdır. Adımları takip etmek için örneğinizi V1.3.4x veya üzeri bir sürüme yükseltin.

Çalışma mantığı

Her SQL deyimi iki aşamadan geçer:

  1. Sorgu iyileştiricisi (QO) sorguyu analiz eder ve bir yürütme planı oluşturur.

  2. Sorgu motoru (QE) bu planı alır, çalıştırır ve sonuçları döndürür.

Yürütme planı, QE'nin kullandığı işleçleri, verilerin bunlar arasındaki akış sırasını ve her adımın tahmini maliyetini açıklar. İyi seçilmiş bir plan daha az kaynak tüketir ve sonuçları daha hızlı döndürür; bu nedenle yürütme planlarını anlamak SQL ayarlamanın temelidir.

Hologres, PostgreSQL ile uyumludur ve aynı EXPLAIN / EXPLAIN ANALYZE sözdizimini kullanır:

Komut Ne gösterir
EXPLAIN QO'nun tahmini planı. Sorgu çalıştırılmaz.
EXPLAIN ANALYZE Gerçek çalışma zamanı planı. Sorgu çalıştırılır ve gerçek zamanlama, satır sayıları ile bellek kullanımı gösterilir.

Hızlı bir tahmin için EXPLAIN kullanın. Doğru teşhisler için EXPLAIN ANALYZE kullanın.

EXPLAIN

Sözdizimi

EXPLAIN <sql>;

Örnek

Aşağıdaki örnek yalnızca gösterim amacıyla bir TPC-H sorgusu kullanır ve resmi TPC-H kıyaslama sonuçlarını temsil etmez.
EXPLAIN SELECT
        l_returnflag,
        l_linestatus,
        sum(l_quantity) AS sum_qty,
        sum(l_extendedprice) AS sum_base_price,
        sum(l_extendedprice * (1 - l_discount)) AS sum_disc_price,
        sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) AS sum_charge,
        avg(l_quantity) AS avg_qty,
        avg(l_extendedprice) AS avg_price,
        avg(l_discount) AS avg_disc,
        count(*) AS count_order
FROM
        lineitem
WHERE
        l_shipdate <= date '1998-12-01' - interval '120' day
GROUP BY
        l_returnflag,
        l_linestatus
ORDER BY
        l_returnflag,
        l_linestatus;

Çıktı:

QUERY PLAN
Sort  (cost=0.00..7795.30 rows=3 width=80)
  Sort Key: l_returnflag, l_linestatus
  ->  Gather  (cost=0.00..7795.27 rows=3 width=80)
        ->  Project  (cost=0.00..7795.27 rows=3 width=80)
              ->  Project  (cost=0.00..7794.27 rows=3 width=104)
                    ->  Final HashAggregate  (cost=0.00..7793.27 rows=3 width=76)
                          Group Key: l_returnflag, l_linestatus
                          ->  Redistribution  (cost=0.00..7792.95 rows=1881 width=76)
                                Hash Key: l_returnflag, l_linestatus
                                ->  Partial HashAggregate  (cost=0.00..7792.89 rows=1881 width=76)
                                      Group Key: l_returnflag, l_linestatus
                                      ->  Local Gather  (cost=0.00..7791.81 rows=44412 width=76)
                                            ->  Decode  (cost=0.00..7791.80 rows=44412 width=76)
                                                  ->  Partial HashAggregate  (cost=0.00..7791.70 rows=44412 width=76)
                                                        Group Key: l_returnflag, l_linestatus
                                                        ->  Project  (cost=0.00..3550.73 rows=584421302 width=33)
                                                              ->  Project  (cost=0.00..2585.43 rows=584421302 width=33)
                                                                    ->  Index Scan using Clustering_index on lineitem  (cost=0.00..261.36 rows=584421302 width=25)
                                                                          Segment Filter: (l_shipdate <= '1998-08-03 00:00:00+08'::timestamp with time zone)
                                                                          Cluster Filter: (l_shipdate <= '1998-08-03 00:00:00+08'::timestamp with time zone)

Çıktıyı okuma

Planı aşağıdan yukarıya doğru okuyun. Her -> bir düğümdür. Veriler yaprak düğümlerden (gerçek veri kaynakları) kök düğüme (son çıktı) doğru yukarı akar.

Her düğüm üç iyileştirici tahmini gösterir:

Alan Açıklama
cost startup_cost..total_cost olarak gösterilen tahmini işleç çalışma süresi. Başlangıç maliyeti, ilk çıktı satırı üretilmeden önceki maliyettir. Toplam maliyet, işlecin tamamlanana kadar çalıştırılması durumunda oluşacak maliyettir. Bir üst düğümün maliyeti tüm alt düğümlerini içerir. Örneğin, Final HashAggregate (cost=0.00..7793.27) için başlangıç maliyeti 0.00 ve toplam maliyet 7793.27 değerindedir.
rows Tablo istatistiklerine dayalı tahmini çıktı satır sayısı. Tarama işlemleri için varsayılan tahmin 1000 değeridir. rows=1000 görürseniz, istatistikler muhtemelen güncel değildir; bunları yenilemek için ANALYZE <tablename> çalıştırın.
width Bayt cinsinden tahmini ortalama satır genişliği. Daha büyük değerler daha geniş çıktı satırlarına işaret eder.

EXPLAIN ANALYZE

Sözdizimi

EXPLAIN ANALYZE <sql>;

Örnek

EXPLAIN ANALYZE SELECT
        l_returnflag,
        l_linestatus,
        sum(l_quantity) AS sum_qty,
        sum(l_extendedprice) AS sum_base_price,
        sum(l_extendedprice * (1 - l_discount)) AS sum_disc_price,
        sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) AS sum_charge,
        avg(l_quantity) AS avg_qty,
        avg(l_extendedprice) AS avg_price,
        avg(l_discount) AS avg_disc,
        count(*) AS count_order
FROM
        lineitem
WHERE
        l_shipdate <= date '1998-12-01' - interval '120' day
GROUP BY
        l_returnflag,
        l_linestatus
ORDER BY
        l_returnflag,
        l_linestatus;

Çıktı:

QUERY PLAN
Sort  (cost=0.00..7795.30 rows=3 width=80)
  Sort Key: l_returnflag, l_linestatus
[id=21 dop=1 time=2427/2427/2427ms rows=4(4/4/4) mem=3/3/3KB open=2427/2427/2427ms get_next=0/0/0ms]
  ->  Gather  (cost=0.00..7795.27 rows=3 width=80)
      [20:1 id=100003 dop=1 time=2426/2426/2426ms rows=4(4/4/4) mem=1/1/1KB open=0/0/0ms get_next=2426/2426/2426ms]
        ->  Project  (cost=0.00..7795.27 rows=3 width=80)
            [id=19 dop=20 time=2427/2426/2425ms rows=4(1/0/0) mem=87/87/87KB open=2427/2425/2425ms get_next=1/0/0ms]
              ->  Project  (cost=0.00..7794.27 rows=0 width=104)
                    ->  Final HashAggregate  (cost=0.00..7793.27 rows=3 width=76)
                          Group Key: l_returnflag, l_linestatus
                        [id=16 dop=20 time=2427/2425/2424ms rows=4(1/0/0) mem=574/570/569KB open=2427/2425/2424ms get_next=1/0/0ms]
                          ->  Redistribution  (cost=0.00..7792.95 rows=1881 width=76)
                                Hash Key: l_returnflag, l_linestatus
                              [20:20 id=100002 dop=20 time=2427/2424/2423ms rows=80(20/4/0) mem=3528/1172/584B open=1/0/0ms get_next=2426/2424/2423ms]
                                ->  Partial HashAggregate  (cost=0.00..7792.89 rows=1881 width=76)
                                      Group Key: l_returnflag, l_linestatus
                                    [id=12 dop=20 time=2428/2357/2256ms rows=80(4/4/4) mem=574/574/574KB open=2428/2357/2256ms get_next=1/0/0ms]
                                      ->  Local Gather  (cost=0.00..7791.81 rows=44412 width=76)
                                          [id=11 dop=20 time=2427/2356/2255ms rows=936(52/46/44) mem=7/6/6KB open=0/0/0ms get_next=2427/2356/2255ms pull_dop=9/9/9]
                                            ->  Decode  (cost=0.00..7791.80 rows=44412 width=76)
                                                [id=8 dop=234 time=2435/1484/5ms rows=936(4/4/4) mem=0/0/0B open=2435/1484/5ms get_next=4/0/0ms]
                                                  ->  Partial HashAggregate  (cost=0.00..7791.70 rows=44412 width=76)
                                                        Group Key: l_returnflag, l_linestatus
                                                      [id=5 dop=234 time=2435/1484/3ms rows=936(4/4/4) mem=313/312/168KB open=2435/1484/3ms get_next=0/0/0ms]
                                                        ->  Project  (cost=0.00..3550.73 rows=584421302 width=33)
                                                            [id=4 dop=234 time=2145/1281/2ms rows=585075720(4222846/2500323/3500) mem=142/141/69KB open=10/1/0ms get_next=2145/1280/2ms]
                                                              ->  Project  (cost=0.00..2585.43 rows=584421302 width=33)
                                                                  [id=3 dop=234 time=582/322/2ms rows=585075720(4222846/2500323/3500) mem=142/142/69KB open=10/1/0ms get_next=582/320/2ms]
                                                                    ->  Index Scan using Clustering_index on lineitem  (cost=0.00..261.36 rows=584421302 width=25)
                                                                          Segment Filter: (l_shipdate <= '1998-08-03 00:00:00+08'::timestamp with time zone)
                                                                          Cluster Filter: (l_shipdate <= '1998-08-03 00:00:00+08'::timestamp with time zone)
                                                                        [id=2 dop=234 time=259/125/1ms rows=585075720(4222846/2500323/3500) mem=1418/886/81KB open=10/1/0ms get_next=253/124/0ms]

ADVICE:
[node id : 1000xxx] distribution key miss match! table lineitem defined distribution keys : l_orderkey; request distribution columns : l_returnflag, l_linestatus;
shuffle data skew in different shards! max rows is 20, min rows is 0

Query id:[300200511xxxx]
======================cost======================
Total cost:[2505] ms
Optimizer cost:[47] ms
Init gangs cost:[4] ms
Build gang desc table cost:[2] ms
Start query cost:[18] ms
- Wait schema cost:[0] ms
- Lock query cost:[0] ms
- Create dataset reader cost:[0] ms
- Create split reader cost:[0] ms
Get the first block cost:[2434] ms
Get result cost:[2434] ms
====================resource====================
Memory: 921(244/230/217) MB,  straggler worker id: 72969760xxx
CPU time: 149772(38159/37443/36736) ms, straggler worker id: 72969760xxx
Physical read bytes: 3345(839/836/834) MB, straggler worker id: 72969760xxx
Read bytes: 41787(10451/10446/10444) MB, straggler worker id: 72969760xxx
DAG instance count: 41(11/10/10), straggler worker id: 72969760xxx
Fragment instance count: 275(70/68/67), straggler worker id: 72969760xxx

Çıktıyı okuma

Çıktı dört bölümden oluşur: QUERY PLAN, ADVICE, Cost ve Resource.

QUERY PLAN

EXPLAIN gibi planı aşağıdan yukarıya okuyun. Her düğüm iki satır gösterir:

  • İyileştirici tahminleri (cost=... rows=... width=...): EXPLAIN ile aynı anlamdadır.

  • Gerçek çalışma zamanı ölçümleri [id=... dop=... time=... rows=... mem=... open=... get_next=...]: Çalıştırma sırasında toplanan gerçek değerler.

Çalışma zamanı ölçüm alanları şunlardır:

Alan Format Açıklama
dag dop (örneğin, 20:20) input:output Giriş ve çıkış eşzamanlılığı oranı. Gather 21:1 21 girişi 1'e birleştirir. Redistribution 20:20 20 çalışan arasında karıştırma yapar. Broadcast 1:21 1 girişi 21 çıkışa yayar.
id Tamsayı İşleç düğümü için benzersiz tanımlayıcı.
dop Tamsayı Paralellik derecesi (dop)—çalıştırma sırasındaki gerçek paralellik. Örneğin parça sayısıyla eşleşir. Local Gather için bu, taranan dosya sayısıdır.
time max/avg/min ms İki aşamaya ayrılmış gerçek çalışma süresi: open (Hash gibi işleçler için tüm aşağı akış verilerini çekme dahil olmak üzere işleç başlatma) ve get_next (her kayıt grubunu getirme).
rows total(max/avg/min) İşleç tarafından çıkarılan satırlar. Maksimum ve minimum arasında büyük bir boşluk veri eğriliğine işaret eder.
mem max/avg/min İşleç çalıştırması sırasında tüketilen bellek. Birikimli değildir—her işlecin değeri bağımsızdır.
Bir işlecin time değeri, alt işleçlerinin kümülatif zamanını içerir. Tek bir işlecin maliyetini izole etmek için alt işlecin zamanını çıkarın. rows ve mem değerleri işleç başına olup kümülatif değildir.

ADVICE

ADVICE bölümü, mevcut çalıştırmadan türetilen otomatik ayarlama önerilerini listeler:

  • Eksik veya uyuşmayan dağıtım anahtarları, kümeleme anahtarları veya bitmap dizinleri (örneğin, Table xxx misses bitmap index)

  • Eski tablo istatistikleri (Table xxx Miss Stats! please run 'analyze xxx')

  • Veri eğriliği (shuffle data skew in different shards! max rows is 20, min rows is 0)

Bu öneriler yalnızca mevcut sorguya dayanır. Değişiklikleri uygulamadan önce bunları kendi iş yükünüzle karşılaştırarak gözden geçirin.

Maliyet dökümü

Maliyet bölümü, sorgu süresinin nerede harcandığını gösterir:

Aşama Açıklama
Total cost Toplam uçtan uca sorgu süresi (ms).
Optimizer cost QO'nun yürütme planını oluşturma süresi.
Build gang desc table cost QO planının yürütme motoru tarafından kullanılan veri yapılarına dönüştürülme süresi.
Init gangs cost Planın ön işleme ve yürütme motoruna istek gönderme süresi.
Start query cost Init gangs sonrası başlatma—şema hizalama, kilitleme ve kurulumu kapsar. Daha fazla ayrıntı:
— Wait schema cost Depolama motorunun (SE) ve ön ucun (FE) şema sürümlerini hizalama süresi. Yüksek değerler genellikle bölümlenmiş üst tablolar üzerinde sık yapılan veri tanımlama dili (DDL) işlemlerine işaret eder; bu durum veri yazma ve sorguları yavaşlatabilir.
— Lock query cost Sorgu kilitlerini edinme süresi. Yüksek değerler kilit çekişmesine işaret eder.
— Create dataset reader cost Dizin veri okuyucularını oluşturma süresi. Yüksek değerler önbellek isabetlerini gösterebilir.
— Create split reader cost Dosyaları açma süresi. Yüksek değerler meta veri önbelleği isabetlerini ve yüksek G/Ç ek yükünü gösterir.
Get the first block cost Start query aşamasının tamamlanmasından ilk kayıt grubunun döndürülmesine kadar geçen süre. Hash Agg gibi çıktı üretmeden önce tüm aşağı akış verilerine ihtiyaç duyan işleçler için bu, toplam Get result maliyetine yakındır.
Get result cost Start query aşamasının tamamlanmasından tüm sonuçların döndürülmesine kadar geçen süre.

Kaynak tüketimi

Kaynak ölçümleri total(max/avg/min) formatını kullanır; burada her değer en yüksek tüketime sahip çalışanı, çalışan başına ortalamayı ve en düşük tüketime sahip çalışanı kapsar.

Ölçüm Açıklama
Memory Toplam tüketilen bellek ve çalışan başına maks/ort/min değerleri.
CPU time Tüm çekirdeklerdeki toplam CPU süresi (ms, yaklaşık). Genel sorgu karmaşıklığını yansıtır.
Physical read bytes Diskten okunan veriler. Sonuçlar önbelleğe alınmadığında gerçekleşir.
Read bytes Fiziksel okumalar ve önbellek isabetleri dahil toplam okunan veriler.
Affected rows Etkilenen satırlar. Yalnızca DML deyimleri için gösterilir.
DAG instance count Yönlendirilmemiş çevrimsiz çizge (DAG) örneklerinin sayısı. Daha yüksek değerler daha fazla paralellik ve karmaşıklığa işaret eder.
Fragment instance count Parça örneklerinin sayısı. Daha yüksek değerler daha fazla yürütme planı segmenti ve dosyasına işaret eder.
straggler_worker_id Her ölçüm için maksimum kaynak tüketimine sahip çalışan düğümünün kimliği.

İşleç referansı

Aşağıdaki tablo her işleci ve rolünü listeler. Ayrıntılar ve ayarlama rehberliği için sonraki bölümlere bakın.

İşleç Kategori Ne yapar
Seq Scan Tarama Tam tablo taraması—dizin kullanılmaz.
Seq Scan on Partitioned Table Tarama Bölümlenmiş bir tabloyu tarar; kaç bölümün seçildiğini gösterir.
Index Scan (Clustering_index) Tarama Bir dizine (segment, kümeleme veya bitmap) vuran sütun deposu taraması.
Index Seek (pk_index) Tarama Birincil anahtar dizini kullanan satır deposu taraması.
Foreign Table Type Tarama Harici tablonun kaynağını belirtir: MaxCompute, OSS veya Hologres.
Filter Filtre Herhangi bir dizine uymayan bir WHERE koşulunu uygular.
Segment Filter Filtre Koşul bir segment dizinine (Event Time Column) uyar.
Cluster Filter Filtre Koşul bir kümeleme dizinine uyar.
Bitmap Filter Filtre Koşul bir bitmap dizinine uyar.
Join Filter Filtre Bir birleştirmeden sonra uygulanan ek filtreleme.
Hash Join (varyantlar) Birleştirme Küçük tablodan oluşturulan bir hash tablosu kullanarak iki tabloyu birleştirir.
Nested Loop Birleştirme Her dış satır için iç tabloyu yineleyen iterasyon. Büyük veri kümeleri için pahalıdır.
Merge Join Birleştirme Birleştirme anahtarlarında önceden sıralanmış iki girişi birleştirir.
Cross Join Birleştirme Küçük tabloyu belleğe yükleyen optimize edilmiş non-equi birleştirme (V3.0+).
Materialize Birleştirme Nested Loop için iç tabloyu arabelleğe alır.
Broadcast Dağıtım Birleştirme için küçük bir tabloyu tüm parçalara kopyalar.
Redistribution Dağıtım Hash veya rastgele dağıtım kullanarak verileri parçalar arasında karıştırır.
Local Gather Birleştirme Tek bir parça içindeki verileri birden fazla dosyadan birleştirir.
Gather Birleştirme Birden fazla parçadaki verileri nihai sonuçta birleştirir.
Partial HashAggregate Toplama Dosyalar ve parçalar içinde toplama yapar.
Final HashAggregate Toplama Parçalar arasındaki kısmi toplamaları birleştirir.
GroupAggregate Toplama Hash kullanmadan önceden sıralanmış verileri toplar.
Sort Diğer Satırları bir veya daha fazla anahtara göre sıralar.
Limit Diğer Çıktı satır sayısını sınırlar.
Append Diğer UNION ALL alt sorgu sonuçlarını birleştirir.
Decode Diğer Hesaplamayı hızlandırmak için metin türü verilerin kodunu çözer veya kodlar.
ExecuteExternalSQL Diğer Bir işlevin veya işlecin HQE yerine PQE'ye geri düştüğünü belirtir.
Exchange Diğer Bir parça içinde veri aktarır. İşlem gerekmez.
Forward Diğer HQE ile PQE veya SQE arasında veri aktarır.
Project Diğer Bir alt sorgu ile dış sorgusu arasında sütun eşlemesi yapar. İşlem gerekmez.

Tarama işleçleri

Seq scan

Seq Scan, herhangi bir dizin kullanmadan tüm tabloyu okur.

EXPLAIN SELECT * FROM public.holo_lineitem_100g;

image

Bölümlenmiş tablolar Seq Scan on Partitioned Table işlecini gösterir ve "Partitions selected: x out of y" raporlar:

EXPLAIN SELECT * FROM public.hologres_parent;

image

Harici tablolar, kaynağı (MaxCompute, OSS veya Hologres) tanımlayan bir Foreign Table Type etiketi içerir:

EXPLAIN SELECT * FROM public.odps_lineitem_100;

image

Index Scan ve Index Seek

Hologres, tablonun depolama formatına bağlı olarak farklı dizin işleçleri kullanır:

  • Index Scan (Clustering_index): Sütun deposu tablolar için kullanılır. Bir sorgu bir dizine uydığında görünür. Plan, hangi dizinin kullanıldığını belirleyen alt işleçleri gösterir: Segment Filter (segment dizini), Cluster Filter (kümeleme dizini) veya Bitmap Filter (bitmap dizini). Daha fazla bilgi için bkz. Sütun deposu ilkeleri. Örnek 1: Sorgu kümeleme dizinine vurur.

    BEGIN;
    CREATE TABLE column_test (
     "id" bigint not null ,
     "name" text not null ,
     "age" bigint not null
    );
    CALL set_table_property('column_test', 'orientation', 'column');
    CALL set_table_property('column_test', 'distribution_key', 'id');
    CALL set_table_property('column_test', 'clustering_key', 'id');
    COMMIT;
    
    INSERT INTO column_test VALUES(1,'tom',10),(2,'tony',11),(3,'tony',12);
    
    EXPLAIN SELECT * FROM column_test WHERE id>2;

    Örnek 2: Dizine alınmamış bir sütunda sorgu—planda Clustering_index yok.

    EXPLAIN SELECT * FROM column_test WHERE age>10;

    image

    image

  • Index Seek (pk_index): Birincil anahtar dizinlerine sahip satır deposu tablolar için kullanılır. Birincil anahtar sorgusu Fixed Plan kullanmadığında görünür. Daha fazla bilgi için bkz. Satır deposu ilkeleri.

    BEGIN;
    CREATE TABLE row_test_1 (
        id bigint not null,
        name text not null,
        class text ,
    PRIMARY KEY (id)
    );
    CALL set_table_property('row_test_1', 'orientation', 'row');
    CALL set_table_property('row_test_1', 'clustering_key', 'name');
    COMMIT;
    INSERT INTO row_test_1 VALUES ('1','qqq','3'),('2','aaa','4'),('3','zzz','5');
    
    BEGIN;
    CREATE TABLE row_test_2 (
        id bigint not null,
        name text not null,
        class text ,
    PRIMARY KEY (id)
    );
    CALL set_table_property('row_test_2', 'orientation', 'row');
    CALL set_table_property('row_test_2', 'clustering_key', 'name');
    COMMIT;
    INSERT INTO row_test_2 VALUES ('1','qqq','3'),('2','aaa','4'),('3','zzz','5');
    
    --primary key index
    EXPLAIN SELECT * FROM (SELECT id FROM row_test_1 WHERE id = 1) t1 JOIN row_test_2 t2 ON t1.id = t2.id;

    image

Filtre işleçleri

Filtre işleçleri, tarama işleçlerinin alt düğümleri olarak görünür ve bir koşulu bir dizine uyup uymadığını gösterir.

Filter

Düz bir Filter koşulun herhangi bir dizine uymadığı anlamına gelir. Performansı artırmak için tablonun dizin yapılandırmasını kontrol edin ve uygun dizinler ekleyin.

Plan One-Time Filter: false gösteriyorsa, sonuç kümesi boştur.
BEGIN;
CREATE TABLE clustering_index_test (
 "id" bigint not null ,
 "name" text not null ,
 "age" bigint not null
);
CALL set_table_property('clustering_index_test', 'orientation', 'column');
CALL set_table_property('clustering_index_test', 'distribution_key', 'id');
CALL set_table_property('clustering_index_test', 'clustering_key', 'age');
COMMIT;

INSERT INTO clustering_index_test VALUES (1,'tom',10),(2,'tony',11),(3,'tony',12);

EXPLAIN SELECT * FROM clustering_index_test WHERE id>2;

image

Segment Filter

Sorgu bir segment dizinine (Event Time Column) uymuştur. Index Scan ile birlikte görünür. Bkz. Event Time Column (segment key).

Cluster Filter

Sorgu bir kümeleme dizinine uymuştur. Bkz. Clustering key.

Bitmap Filter

Sorgu bir bitmap dizinine uymuştur. Bkz. Bitmap index.

Join Filter

Bir birleştirme işleminden sonra ek filtreleme uygular.

Decode

Decode işleci, hesaplamayı hızlandırmak için metin ve benzeri veri türlerinin kodunu çözer veya kodlar.

Local Gather ve Gather

Hologres'teki veriler parçalar içindeki dosyalar olarak saklanır. Local Gather, tek bir parça içindeki verileri birden fazla dosyadan birleştirir. Gather, birden fazla parçadaki verileri nihai sonuçta birleştirir.

EXPLAIN SELECT * FROM public.lineitem;

image

Redistribution

Redistribution işleci, hash veya rastgele dağıtım kullanarak verileri parçalar arasında karıştırır. Genellikle şu durumlarda görünür:

  • Dağıtım anahtarlarının eksik olduğu veya uyuşmadığı JOIN, COUNT DISTINCT veya GROUP BY sorguları—veriler yerel olarak birleştirilmek yerine parçalar arasında karıştırılmalıdır. Çoklu tablo birleştirmelerinde Redistribution, yerel birleştirmenin kullanılmadığı ve performansın düştüğü anlamına gelir.

  • Orijinal alan türünü değiştiren ifadeler (dönüşümler gibi) kullanan JOIN veya GROUP BY anahtarları, bu da yerel birleştirmeleri engeller.

Örnek 1: Uyuşmayan dağıtım anahtarları Redistribution'a neden olur.

BEGIN;
CREATE TABLE tbl1(
a int not null,
b text not null
);
CALL set_table_property('tbl1', 'distribution_key', 'a');
CREATE TABLE tbl2(
c int not null,
d text not null
);
CALL set_table_property('tbl2', 'distribution_key', 'd');
COMMIT;

EXPLAIN SELECT * FROM tbl1  JOIN tbl2 ON tbl1.a=tbl2.c;

Birleştirme koşulu tbl1.a=tbl2.c şeklindedir, ancak dağıtım anahtarları a ve d şeklindedir—bu uyuşmazlık bir veri karıştırmayı zorlar.

image

Redistribution görünüyorsa, dağıtım anahtarlarının doğru ayarlandığını kontrol edin. Bkz. Distribution key.

Örnek 2: Tür değiştiren ifade içeren bir birleştirme anahtarı yerel birleştirmeleri engeller.

image

Bunu önlemek için birleştirme anahtarlarında ifadelerden kaçının.

Birleştirme işleçleri

Hash Join

Hash Join, bellekte küçük tablodan bir hash tablosu oluşturur, ardından büyük tablodan gelen verilerle satır satır sorgular.

Tür Açıklama
Hash Left Join Sağ tablo sütunları için eşleşmeyen NULL değerlerle sol tablodaki tüm satırları döndürür.
Hash Right Join Sol tablo sütunları için eşleşmeyen NULL değerlerle sağ tablodaki tüm satırları döndürür.
Hash Inner Join Yalnızca birleştirme koşulunu karşılayan satırları döndürür.
Hash Full Join Eşleşmeyen tarafta NULL değerlerle her iki tablodaki tüm satırları döndürür.
Hash Anti Join Eşleşmesi olmayan sürücü tablosundaki satırları döndürür—NOT EXISTS için kullanılır.
Hash Semi Join Sürücü tablosundan her eşleşme için bir satır döndürür—EXISTS için kullanılır. Yinelenen yoktur.

Bir Hash Join'i analiz ederken ayrıca şunları kontrol edin:

  • hash cond: Birleştirme koşulu, örneğin hash cond (tmp.a=tmp1.b).

  • hash key: Parçalar arasında hash hesaplama için kullanılan anahtar, tipik olarak GROUP BY anahtarıdır.

Küçük tablo hash tablosu olmalıdır. Doğrulamak için planda hash olarak etiketlenen tabloyu arayın—aşağıdan yukarıya okurken alt dalda görünür. Daha büyük tabloyu hash tablosu olarak kullanmak aşırı bellek tüketir.

Ayarlama: istatistikleri güncelleyin

Eski istatistikler, QO'nun tablo boyutlarını yanlış değerlendirmesine neden olur. Örneğin, istatistikler aslında 1 milyon satırı olan bir tablo için rows=1000 gösterirse, hash tablosu olarak yanlış tablo seçilir.

BEGIN ;
CREATE TABLE public.hash_join_test_1 (
    a integer not null,
    b text not null
);
CALL set_table_property('public.hash_join_test_1', 'distribution_key', 'a');
CREATE TABLE public.hash_join_test_2 (
    c integer not null,
    d text not null
);
CALL set_table_property('public.hash_join_test_2', 'distribution_key', 'c');
COMMIT ;

INSERT INTO hash_join_test_1 SELECT i, i+1 FROM generate_series(1, 10000) AS s(i);
INSERT INTO hash_join_test_2 SELECT i, i::text FROM generate_series(10, 1000000) AS s(i);

EXPLAIN SELECT * FROM hash_join_test_1 tbl1  JOIN hash_join_test_2 tbl2 ON tbl1.a=tbl2.c;

Plan, yanlışlıkla daha büyük olan hash_join_test_2 tablosunu hash tablosu olarak kullanır:

image

İstatistikler yenilendikten sonra plan doğru şekilde daha küçük tabloyu seçer:

ANALYZE hash_join_test_1;
ANALYZE hash_join_test_2;

image

Ayarlama: karmaşık sorgular için birleştirme sırasını ayarlayın

İstatistiklerin yenilenmesi çoğu birleştirme sırası sorununu çözer. Beş veya daha fazla tablo içeren karmaşık birleştirmeler için QO, en iyi planı bulmak için önemli ölçüde zaman harcayabilir. Bunu kontrol etmek için optimizer_join_order Grand Unified Configuration (GUC) parametresini kullanın:

SET optimizer_join_order = '<value>';
Değer Açıklama
exhaustive (varsayılan) Tüm birleştirme sırası permütasyonlarını değerlendirir. Optimal planlar üretir ancak çok sayıda tablo için iyileştirici ek yükünü artırır.
query SQL'de yazıldığı gibi birleştirme sırasını kullanır. Küçük tablolar (100 milyondan az satır) içeren birleştirmeler için QO ek yükünü azaltır. Veritabanı düzeyinde ayarlamayın—tüm birleştirmeleri etkiler.
greedy Orta düzey QO ek yüküyle iyi bir birleştirme sırası bulmak için açgözlü bir algoritma kullanır.

Nested Loop Join ve Materialize

Nested Loop işleci, dış tabloyu satır satır okur ve her eşleşme için iç tabloyu arar—temelde bir Kartezyen çarpımdır. İç tablo genellikle planda bir Materialize işleci gösterir.

BEGIN;
CREATE TABLE public.nestedloop_test_1 (
    a integer not null,
    b integer not null
);
CALL set_table_property('public.nestedloop_test_1', 'distribution_key', 'a');
CREATE TABLE public.nestedloop_test_2 (
    c integer not null,
    d text not null
);
CALL set_table_property('public.nestedloop_test_2', 'distribution_key', 'c');
COMMIT;

INSERT INTO nestedloop_test_1 SELECT i, i+1 FROM generate_series(1, 10000) AS s(i);
INSERT INTO nestedloop_test_2 SELECT i, i::text FROM generate_series(10, 1000000) AS s(i);

EXPLAIN SELECT * FROM nestedloop_test_1 tbl1,nestedloop_test_2 tbl2 WHERE tbl1.a>tbl2.c;

image

Nested Loop maliyetini azaltmak için:

  • İç tablonun taranma sayısını sınırlamak için dış sonuç kümesini küçük tutun.

  • Mümkün olduğunca non-equi birleştirmelerden kaçının—genellikle Nested Loop planları üretirler.

Cross Join

V3.0'dan başlayarak, Cross Join işleci küçük bir tablo içeren non-equi birleştirme senaryolarını optimize eder. Her dış satır için iç durumu sıfırlayan Nested Loop'un aksine, Cross Join tüm küçük tabloyu belleğe yükler ve büyük tabloyu üzerinden akıtır. Bu çok daha hızlıdır ancak daha fazla bellek kullanır.

image

Cross Join'u devre dışı bırakmak için:

-- Disable for the current session
SET hg_experimental_enable_cross_join_rewrite = off;

-- Disable at the database level (takes effect for new connections)
ALTER database <database name> hg_experimental_enable_cross_join_rewrite = off;

Merge Join

Merge Join, girişlerinin birleştirme anahtarlarında önceden sıralanmış olmasını gerektirir. Hologres, giriş verilerinin zaten sıralı olduğu sorgular için Merge Join'i seçebilir.

Broadcast

Broadcast işleci, küçük bir tablonun büyük bir tabloyla birleştirildiği Broadcast Join senaryolarında kullanılan bir tabloyu tüm parçalara kopyalar. QO, Broadcast maliyetini Redistribution ile karşılaştırır ve daha ucuz olanı seçer.

Tablo küçükse ve örnek az parçaya sahipse (örneğin, 5 parça) Broadcast maliyet açısından etkilidir.

BEGIN;
CREATE TABLE broadcast_test_1 (
    f1 int,
    f2 int);
CALL set_table_property('broadcast_test_1','distribution_key','f2');
CREATE TABLE broadcast_test_2 (
    f1 int,
    f2 int);
COMMIT;

INSERT INTO broadcast_test_1 SELECT i AS f1, i AS f2 FROM generate_series(1, 30)i;
INSERT INTO broadcast_test_2 SELECT i AS f1, i AS f2 FROM generate_series(1, 30000)i;

ANALYZE broadcast_test_1;
ANALYZE broadcast_test_2;

EXPLAIN SELECT * FROM broadcast_test_1 t1, broadcast_test_2 t2 WHERE t1.f1=t2.f1;

image

Küçük olmayan bir tablo için Broadcast görünüyorsa, muhtemel neden eski istatistiklerdir (örneğin, istatistikler 1.000 satır gösterirken gerçek tabloda 1 milyon satır vardır). Bunları yenilemek için ANALYZE <tablename> çalıştırın.

Shard prune ve Shards selected

  • Shard prune: QO'nun ilgili parçaları nasıl seçtiğini gösterir. QO uygun yöntemi otomatik olarak seçer.

    • lazily: Parçalar önce ID ile işaretlenir ve hesaplama sırasında seçilir.

    • eagerly: Yalnızca eşleşen parçalar hemen seçilir; ilgisiz parçalar atlanır.

  • Shards selected: Kullanılan parça sayısı. Örneğin, 1 out of 20 toplam 20 parçadan 1 parçanın seçildiği anlamına gelir.

ExecuteExternalSQL

Hologres üç sorgu motoru bileşenine sahiptir: Hologres Query Engine (HQE), PostgreSQL Query Engine (PQE) ve Shard Query Engine (SQE). HQE özel motordur. HQE bir işlevi veya işleci desteklemediğinde, PQE bunu işler—bu bir performans maliyeti doğurur. Plandaki ExecuteExternalSQL işleci PQE çalıştırmasını işaretler.

Örnek 1: ::timestamp dönüşümü PQE tarafından işlenir.

CREATE TABLE pqe_test(a text);
INSERT INTO pqe_test VALUES ('2023-01-28 16:25:19.082698+08');
EXPLAIN SELECT a::timestamp FROM pqe_test;

image

Örnek 2: ::timestamp ifadesini to_timestamp olarak yeniden yazmak HQE kullanır—planda ExecuteExternalSQL yoktur.

EXPLAIN SELECT to_timestamp(a,'YYYY-MM-DD HH24:MI:SS') FROM pqe_test;

image

Çalıştırma planlarında PQE'yi tetikleyen işlevleri belirleyin, ardından bunları HQE uyumlu eşdeğerleri kullanacak şekilde yeniden yazın. Yaygın yeniden yazma örnekleri için bkz. Sorgu performansını optimize etme.

Hologres, her sürümle birlikte daha fazla PQE işlemini HQE'ye iter. Bazı işlevler yükseltmeden sonra otomatik olarak HQE kullanabilir. İşlev sürüm notları konusuna bakın.

Toplama işleçleri

Hologres çoğu toplama işlemi için HashAggregate kullanır. HashAggregate, paralel toplama için verileri parçalar arasında dağıtır, ardından sonuçları Gather ile birleştirir.

Büyük veri kümeleri için Hologres çok aşamalı HashAggregate kullanır:

  • Partial HashAggregate: Dosyalar ve parçalar içinde toplama yapar.

  • Final HashAggregate: Parçalar arasındaki kısmi sonuçları birleştirir.

Veriler GROUP BY anahtarlarında önceden sıralandığında GroupAggregate kullanılır.

EXPLAIN SELECT
        sum(l_extendedprice * l_discount) AS revenue
FROM
        lineitem
WHERE
        l_shipdate >= date '1996-01-01'
        AND l_shipdate < date '1996-01-01' + interval '1' year
        AND l_discount BETWEEN 0.02 - 0.01 AND 0.02 + 0.01
        AND l_quantity < 24;

image

QO, veri hacmine göre otomatik olarak tek aşamalı veya çok aşamalı HashAggregate seçer. EXPLAIN ANALYZE bir Aggregate işleci için yüksek süre gösteriyorsa ancak QO yalnızca parça düzeyinde toplama seçtiyse, çok aşamalı toplamayı zorlayın:

SET optimizer_force_multistage_agg = on;

Sort

Sort işleci, satırları artan (ASC) veya azalan (DESC) sırada düzenler; tipik olarak ORDER BY yan tümcelerinden gelir.

EXPLAIN SELECT l_shipdate FROM public.lineitem ORDER BY l_shipdate;

image

Büyük sıralama işlemleri önemli kaynaklar tüketir. Mümkün olduğunda büyük veri kümelerini sıralamaktan kaçının.

Limit

Limit işleci, çıktı satır sayısını sınırlar. Yalnızca nihai çıktıyı kontrol eder, taranan satır sayısını değil. Gerçek tarama hacmini anlamak için Limit'in Seq Scan düğümüne itilip itilmediğini kontrol edin.

EXPLAIN SELECT * FROM public.lineitem limit 1;

image

Limit hakkında notlar:

  • Tüm Limit işleçleri itilmez. Taranan satırları azaltmak için filtre koşulları ekleyin.

  • Çok büyük LIMIT değerlerinden (yüz binlerce veya daha fazla) kaçının—itilseler bile tarama süresini artırırlar.

Append

Append işleci, UNION ALL alt sorgularının sonuçlarını birleştirir.

Exchange

Exchange işleci, bir parça içinde veri aktarır. İşlem gerekmez.

Forward

Forward işleci, HQE ile PQE veya SQE arasında veri aktarır. HQE+PQE veya HQE+SQE kombinasyonlarını kullanan planlarda görünür.

Project

Project işleci, bir alt sorgu ile dış sorgusu arasındaki sütun eşlemesini temsil eder. İşlem gerekmez.

Yaygın performans sorunları

Yürütme planında belirli bir belirti gördüğünüzde bu bölümü hızlı referans olarak kullanın.

Belirti Olası neden Ne yapılmalı
Taramada rows=1000 Eski istatistikler ANALYZE <tablename> çalıştırın
Birleştirmede Redistribution Dağıtım anahtarı uyuşmazlığı veya birleştirme anahtarında tür değiştiren ifade Dağıtım anahtarlarını birleştirme anahtarlarıyla hizalayın; birleştirme anahtarlarında ifadelerden kaçının. Bkz. Distribution key.
Hash Join'de büyük tablo hash tablosu Eski istatistikler Her iki tabloda da ANALYZE çalıştırın
Yalnızca parça düzeyinde toplamayla yüksek Aggregate süresi Tek aşamalı toplama için veri hacmi çok büyük optimizer_force_multistage_agg = on ayarlayın
ExecuteExternalSQL görünür HQE tarafından desteklenmeyen işlev veya işleç, PQE'ye geri düşüyor İfadeyi HQE uyumlu bir işlev kullanacak şekilde yeniden yazın. Bkz. Sorgu performansını optimize etme.
Büyük tablolarda Nested Loop Non-equi birleştirme koşulu Mümkün olduğunda equi-join'e yeniden yazın; dış sonuç kümesini küçük tutun
Hash işleçlerinde yüksek open süresi Hash tablosu oluşturma yavaş—büyük iç tablo veya yavaş alt düğümler İstatistikleri ve alt işleç sürelerini kontrol edin; birleştirme sırasını düşünün
Maksimum ve minimum rows veya mem arasında büyük boşluk Parçalar arasında veri eğriliği ADVICE bölümünü kontrol edin; dağıtım anahtarlarını ayarlayın
Yüksek Wait schema maliyeti Bölümlenmiş üst tablolar üzerinde sık DDL DDL sıklığını azaltın
Yüksek Lock query maliyeti Kilit çekişmesi Eşzamanlı sorguları araştırın

Sonraki adımlar