Tüm Ürünler
Search
Belge Merkezi

MaxCompute:EXPLAIN

Son Güncelleme:Oct 10, 2026

EXPLAIN deyimi, MaxCompute SQL'de bir SELECT sorgusunun yürütme planını görüntüler. Bu sayede sorgu ifadelerindeki veya tablo yapılarındaki performans darboğazlarını tespit edebilirsiniz.

Bir sorgu, her biri bir veya daha fazla görev içeren bir veya daha fazla işe (job) karşılık gelir. EXPLAIN çıktısı, işlerin, görevlerin ve operatörlerin birbirleriyle olan ilişkisini ortaya koyarak SQL kodunuzu anlamanıza ve optimize etmenize yardımcı olur.

Söz dizimi

EXPLAIN <query>;

query: Zorunludur. Bir SELECT ifadesidir. Daha fazla bilgi için bkz. SELECT söz dizimi.

Çıktı yapısı

EXPLAIN çıktısı üç bölümden oluşur:

  1. İş bağımlılıkları — Tüm işleri ve bunların yürütülme sırasını listeler. job0 is root job ifadesi, sorgunun tek bir kök iş gerektirdiğini gösterir.

  2. Görev bağımlılıkları — Her iş içindeki görevleri ve bunların bağımlılıklarını listeler. Aşağıdaki çıktı, job0 işinin M1, M2 ve J3_1_2_Stg1 olmak üzere üç görev içerdiğini; ayrıca MaxCompute'ün J3_1_2_Stg1 görevini yalnızca M1 ve M2 tamamlandıktan sonra çalıştırdığını gösterir.

        In Job job0:
        root Tasks: M1, M2
        J3_1_2_Stg1 depends on: M1, M2
  3. Operatör ayrıntıları — Her görev içindeki operatörleri ve yürütme semantiğini açıklar. Data source satırı görevin giriş verisini tanımlar. Sonraki her satır bir operatörü ve parametrelerini temsil eder; girintiler operatör işlem hattındaki hiyerarşiyi gösterir.

        In Task M2:
            Data source: mf_mc_bj.sale_detail_jt/sale_date=2013/region=china
            TS: mf_mc_bj.sale_detail_jt/sale_date=2013/region=china
                FIL: ISNOTNULL(customer_id)
                    RS: order: +
                        nullDirection: *
                        optimizeOrderBy: False
                        valueDestLimit: 0
                        dist: HASH
                        keys:
                              customer_id
                        values:
                              customer_id (string)
                              total_price (double)
                        partitions:
                              customer_id

Görev adlandırma kuralları


Bileşen


Anlamı


Örnek


İlk harf


Görev türü: M (MapTask), R (ReduceTask), J (JoinTask) veya L (LocalWork)


M2Stg1 bir map görevidir


İlk harften sonraki rakam


Sorgu içinde benzersiz olan görev kimliği


M2 görevinin kimliği 2'dir


Alt çizgi ile ayrılmış rakamlar


Görevin doğrudan bağımlılıkları


J3_1_2_Stg1 görevi M1 ve M2'ye bağlıdır

Operatörler


Operatör


Kısaltma


SQL yan tümcesi


Açıklama


TableScanOperator


TS


FROM


Giriş tablosunu tarar. Çıktıda giriş tablosunun takma adı gösterilir.


SelectOperator


SEL


SELECT


Sütunları bir sonraki operatöre yansıtır. Sütunlar <alias>.<column_name> biçiminde, ifadeler bir işlev listesi olarak (örneğin, func1(arg1_1, arg1_2, func2(arg2_1, arg2_2))) ve sabit değerler ise değişmez değerleri olarak görüntülenir.


FilterOperator


FIL


WHERE


Bir WHERE ifadesine göre satırları filtreler. Görüntüleme biçimi SelectOperator'a benzer.


JoinOperator


JOIN


JOIN


Tabloları birleştirir. Çıktıda hangi tabloların birleştirildiği ve birleştirme yöntemi gösterilir.


GroupByOperator


AGGREGATE


Toplama işlevleri


Toplama işlemi gerçekleştirir. Sorguda toplama işlevleri bulunduğunda görünür. Çıktıda toplama işlevinin içeriği gösterilir.


ReduceSinkOperator


RS


--


Görevler arasında veri dağıtımı sağlar. Bir görevin çıktısı başka bir göreve beslendiğinde, o görevin sonunda görünür. Çıktıda sıralama düzeni, dağıtım anahtarları, değerler ve hash sütunları gösterilir.


FileSinkOperator


FS


INSERT


Nihai sonuçları depolama alanına yazar. INSERT ifadeleri için çıktıda hedef tablo adı gösterilir.


LimitOperator


LIM


LIMIT


Döndürülen satır sayısını sınırlar.


MapjoinOperator


HASHJOIN


JOIN


Büyük tablolarda map tarafında birleştirme işlemi gerçekleştirir. JoinOperator'a benzer.

Her operatör satırı, işlem hattının o noktasındaki tahmini satır sayısını ve veri boyutunu gösteren bir Statistics satırı da üretir. Örneğin, Statistics: Num rows: 3.0, Data size: 324.0 bilgisi, iyileştiricinin operatörün kaç satır üreteceğini beklediğini gösterir. Bu tahminleri kullanarak, beklenenden çok daha fazla veri işleyen operatörleri tespit edebilirsiniz; bu durum genellikle eksik bir filtrenin veya eğri bir birleştirme anahtarının göstergesidir.

ReduceSinkOperator (RS) çıktısı aşağıdaki alanları içerir:


Alan


Açıklama


order


Her anahtar için sıralama yönü: + (artan) veya - (azalan).


nullDirection


Null değerlerin null olmayan değerlere göre nasıl sıralandığı: * (varsayılan sıra), a (null önce) veya z (null sonra).


optimizeOrderBy


Veriler zaten sıralı olduğu için iyileştiricinin tam sıralamayı atlayıp atlayamayacağı. True değeri, sıralamanın atlandığını gösterir.


valueDestLimit


Aşağı akış görevine gönderilen maksimum satır sayısı. 0 sınırı olmadığını gösterir. Varsa LIMIT yan tümcesine karşılık gelir.


dist


Dağıtım yöntemi: HASH satırları anahtar sütunlarının hash değerine göre böler; BROADCAST tüm satırları her aşağı akış görevine kopyalar.


keys


Verileri görevler arasında bölmek ve sıralamak için kullanılan sütunlar.


values


Aşağı akış görevine aktarılan sütunlar.


partitions


Her satırın hangi göreve gideceğini belirlemek için kullanılan sütunlar.

Sınırlamalar

Bir sorgu karmaşık olduğunda ve EXPLAIN çıktısı 4 MB'ı aştığında, üst katman uygulama API limiti aşılır ve çıktı kesilir. Bu durumu aşmak için sorguyu daha küçük alt sorgulara ayırın ve her biri için EXPLAIN komutunu ayrı ayrı çalıştırın.

Örnekler

Örnek verileri hazırlama

sale_detail ve sale_detail_jt adlı iki bölümlenmiş tablo oluşturun ve örnek veriler ekleyin.

-- Create two partitioned tables named sale_detail and sale_detail_jt.
CREATE TABLE if NOT EXISTS sale_detail
(
shop_name     STRING,
customer_id   STRING,
total_price   DOUBLE
)
PARTITIONED BY (sale_date STRING, region STRING);

CREATE TABLE if NOT EXISTS sale_detail_jt
(
shop_name     STRING,
customer_id   STRING,
total_price   DOUBLE
)
PARTITIONED BY (sale_date STRING, region STRING);

-- Add partitions to the two tables.
ALTER TABLE sale_detail ADD PARTITION (sale_date='2013', region='china') PARTITION (sale_date='2014', region='shanghai');
ALTER TABLE sale_detail_jt ADD PARTITION (sale_date='2013', region='china');

-- Insert data into the tables.
INSERT INTO sale_detail PARTITION (sale_date='2013', region='china') VALUES ('s1','c1',100.1),('s2','c2',100.2),('s3','c3',100.3);
INSERT INTO sale_detail PARTITION (sale_date='2014', region='shanghai') VALUES ('null','c5',null),('s6','c6',100.4),('s7','c7',100.5);
INSERT INTO sale_detail_jt PARTITION (sale_date='2013', region='china') VALUES ('s1','c1',100.1),('s2','c2',100.2),('s5','c2',100.2);

Verileri doğrulayın:

SET odps.sql.allow.fullscan=true;
SELECT * FROM sale_detail;
+------------+-------------+-------------+------------+------------+
| shop_name  | customer_id | total_price | sale_date  | region     |
+------------+-------------+-------------+------------+------------+
| s1         | c1          | 100.1       | 2013       | china      |
| s2         | c2          | 100.2       | 2013       | china      |
| s3         | c3          | 100.3       | 2013       | china      |
| null       | c5          | NULL        | 2014       | shanghai   |
| s6         | c6          | 100.4       | 2014       | shanghai   |
| s7         | c7          | 100.5       | 2014       | shanghai   |
+------------+-------------+-------------+------------+------------+
SET odps.sql.allow.fullscan=true;
SELECT * FROM sale_detail_jt;
+------------+-------------+-------------+------------+------------+
| shop_name  | customer_id | total_price | sale_date  | region     |
+------------+-------------+-------------+------------+------------+
| s1         | c1          | 100.1       | 2013       | china      |
| s2         | c2          | 100.2       | 2013       | china      |
| s5         | c2          | 100.2       | 2013       | china      |
+------------+-------------+-------------+------------+------------+

JOIN işlemi için bölümlenmemiş bir tablo oluşturun:

SET odps.sql.allow.fullscan=true;
CREATE TABLE shop AS SELECT shop_name, customer_id, total_price FROM sale_detail;

Örnek 1: Standart JOIN ve toplama işlemi

Bu örnekte, sale_detail_jt ve sale_detail tabloları arasında INNER JOIN gerçekleştiren, sonuçları gruplayan ve limit ile sıralama uygulayan bir sorgu üzerinde EXPLAIN çalıştırılır.

Sorgu:

SELECT a.customer_id AS ashop, SUM(a.total_price) AS ap,COUNT(b.total_price) AS bp
FROM (SELECT * FROM sale_detail_jt WHERE sale_date='2013' AND region='china') a
INNER JOIN (SELECT * FROM sale_detail WHERE sale_date='2013' AND region='china') b
ON a.customer_id=b.customer_id
GROUP BY a.customer_id
ORDER BY a.customer_id
LIMIT 10;

EXPLAIN çalıştırın:

EXPLAIN
SELECT a.customer_id AS ashop, SUM(a.total_price) AS ap,COUNT(b.total_price) AS bp
FROM (SELECT * FROM sale_detail_jt WHERE sale_date='2013' AND region='china') a
INNER JOIN (SELECT * FROM sale_detail WHERE sale_date='2013' AND region='china') b
ON a.customer_id=b.customer_id
GROUP BY a.customer_id
ORDER BY a.customer_id
LIMIT 10;

Çıktı:

job0 is root job

In Job job0:
root Tasks: M1
M2_1 depends on: M1
R3_2 depends on: M2_1
R4_3 depends on: R3_2

In Task M1:
    Data source: doc_****.default.sale_detail/sale_date=2013/region=china
    TS: doc_****.default.sale_detail/sale_date=2013/region=china
        Statistics: Num rows: 3.0, Data size: 324.0
        FIL: ISNOTNULL(customer_id)
            Statistics: Num rows: 2.7, Data size: 291.6
            RS: valueDestLimit: 0
                dist: BROADCAST
                keys:
                values:
                      customer_id (string)
                      total_price (double)
                partitions:

                Statistics: Num rows: 2.7, Data size: 291.6

In Task M2_1:
    Data source: doc_****.default.sale_detail_jt/sale_date=2013/region=china
    TS: doc_****.default.sale_detail_jt/sale_date=2013/region=china
        Statistics: Num rows: 3.0, Data size: 324.0
        FIL: ISNOTNULL(customer_id)
            Statistics: Num rows: 2.7, Data size: 291.6
            HASHJOIN:
                     Filter1 INNERJOIN StreamLineRead1
                     keys:
                         0:customer_id
                         1:customer_id
                     non-equals:
                         0:
                         1:
                     bigTable: Filter1

                Statistics: Num rows: 3.6450000000000005, Data size: 787.32
                RS: order: +
                    nullDirection: *
                    optimizeOrderBy: False
                    valueDestLimit: 0
                    dist: HASH
                    keys:
                          customer_id
                    values:
                          customer_id (string)
                          total_price (double)
                          total_price (double)
                    partitions:
                          customer_id

                    Statistics: Num rows: 3.6450000000000005, Data size: 422.82000000000005

In Task R3_2:
    AGGREGATE: group by:customer_id
     UDAF: SUM(total_price) (__agg_0_sum)[Complete],COUNT(total_price) (__agg_1_count)[Complete]
        Statistics: Num rows: 1.0, Data size: 116.0
        RS: order: +
            nullDirection: *
            optimizeOrderBy: True
            valueDestLimit: 10
            dist: HASH
            keys:
                  customer_id
            values:
                  customer_id (string)
                  __agg_0 (double)
                  __agg_1 (bigint)
            partitions:

            Statistics: Num rows: 1.0, Data size: 116.0

In Task R4_3:
    SEL: customer_id,__agg_0,__agg_1
        Statistics: Num rows: 1.0, Data size: 116.0
        SEL: customer_id ashop, __agg_0 ap, __agg_1 bp, customer_id
            Statistics: Num rows: 1.0, Data size: 216.0
            FS: output: Screen
                schema:
                  ashop (string)
                  ap (double)
                  bp (bigint)

                Statistics: Num rows: 1.0, Data size: 116.0

OK

Yürütme planı dört görev göstermektedir:

  • M1 — sale_detail tablosunu tarar, null customer_id değerlerini filtreler ve verileri tüm aşağı akış görevlerine yayınlar (dist: BROADCAST). Boş keys ve partitions alanları, verilerin bölümlenmediğini — yani her satırın her yere gönderildiğini — doğrular.

  • M2_1 — sale_detail_jt tablosunu tarar, null customer_id değerlerini filtreler ve M1'den gelen yayınlanmış verilerle map tarafında hash birleştirme (HASHJOIN) gerçekleştirir. Sonuçlar, aşağı akış reduce görevi için customer_id anahtarına göre hash ile bölümlenir.

  • R3_2 — GROUP BY customer_id ile toplama işlemi yapar; SUM(total_price) ve COUNT(total_price) hesaplar. Her ikisi de Complete modunda çalışır; bu, kısmi ön toplama olmadan tam toplamanın tek aşamada gerçekleştiği anlamına gelir.

  • R4_3 — Nihai sütunları seçer, bunlara takma ad atar (ashop, ap, bp) ve çıktıyı ekrana yazar.

Örnek 2: Map tarafı birleştirme (MAPJOIN ipucu)

Bu örnekte, eşitsizlik içeren bir birleştirme koşuluyla (a.total_price < b.total_price) map tarafı birleştirmeyi zorlamak için /*+ mapjoin(a) */ ipucu kullanılır.

Sorgu:

SELECT /*+ mapjoin(a) */
       a.customer_id AS ashop, SUM(a.total_price) AS ap,COUNT(b.total_price) AS bp
FROM (SELECT * FROM sale_detail_jt
WHERE sale_date='2013' AND region='china') a
INNER JOIN (SELECT * FROM sale_detail WHERE sale_date='2013' AND region='china') b
ON a.total_price<b.total_price
GROUP BY a.customer_id
ORDER BY a.customer_id
LIMIT 10;

EXPLAIN çalıştırın:

EXPLAIN
SELECT /*+ mapjoin(a) */
       a.customer_id AS ashop, SUM(a.total_price) AS ap,COUNT(b.total_price) AS bp
FROM (SELECT * FROM sale_detail_jt
WHERE sale_date='2013' AND region='china') a
INNER JOIN (SELECT * FROM sale_detail WHERE sale_date='2013' AND region='china') b
ON a.total_price<b.total_price
GROUP BY a.customer_id
ORDER BY a.customer_id
LIMIT 10;

Çıktı:

job0 is root job

In Job job0:
root Tasks: M1
M2_1 depends on: M1
R3_2 depends on: M2_1
R4_3 depends on: R3_2

In Task M1:
    Data source: doc_****.sale_detail_jt/sale_date=2013/region=china
    TS: doc_****.sale_detail_jt/sale_date=2013/region=china
        Statistics: Num rows: 3.0, Data size: 324.0
        RS: valueDestLimit: 0
            dist: BROADCAST
            keys:
            values:
                  customer_id (string)
                  total_price (double)
            partitions:

            Statistics: Num rows: 3.0, Data size: 324.0

In Task M2_1:
    Data source: doc_****.sale_detail/sale_date=2013/region=china
    TS: doc_****.sale_detail/sale_date=2013/region=china
        Statistics: Num rows: 3.0, Data size: 24.0
        HASHJOIN:
                 StreamLineRead1 INNERJOIN TableScan2
                 keys:
                     0:
                     1:
                 non-equals:
                     0:
                     1:
                 bigTable: TableScan2

            Statistics: Num rows: 9.0, Data size: 1044.0
            FIL: LT(total_price,total_price)
                Statistics: Num rows: 6.75, Data size: 783.0
                AGGREGATE: group by:customer_id
                 UDAF: SUM(total_price) (__agg_0_sum)[Partial_1],COUNT(total_price) (__agg_1_count)[Partial_1]
                    Statistics: Num rows: 2.3116438356164384, Data size: 268.1506849315069
                    RS: order: +
                        nullDirection: *
                        optimizeOrderBy: False
                        valueDestLimit: 0
                        dist: HASH
                        keys:
                              customer_id
                        values:
                              customer_id (string)
                              __agg_0_sum (double)
                              __agg_1_count (bigint)
                        partitions:
                              customer_id

                        Statistics: Num rows: 2.3116438356164384, Data size: 268.1506849315069

In Task R3_2:
    AGGREGATE: group by:customer_id
     UDAF: SUM(__agg_0_sum)[Final] __agg_0,COUNT(__agg_1_count)[Final] __agg_1
        Statistics: Num rows: 1.6875, Data size: 195.75
        RS: order: +
            nullDirection: *
            optimizeOrderBy: True
            valueDestLimit: 10
            dist: HASH
            keys:
                  customer_id
            values:
                  customer_id (string)
                  __agg_0 (double)
                  __agg_1 (bigint)
            partitions:

            Statistics: Num rows: 1.6875, Data size: 195.75

In Task R4_3:
    SEL: customer_id,__agg_0,__agg_1
        Statistics: Num rows: 1.6875, Data size: 195.75
        SEL: customer_id ashop, __agg_0 ap, __agg_1 bp, customer_id
            Statistics: Num rows: 1.6875, Data size: 364.5
            FS: output: Screen
                schema:
                  ashop (string)
                  ap (double)
                  bp (bigint)

                Statistics: Num rows: 1.6875, Data size: 195.75

OK

1. Örnekten temel farklar şunlardır:

  • M1, mapjoin ipucuyla belirtilen sale_detail_jt tablosunu filtre uygulamadan yayınlar. Bunun nedeni, eşitsizlik içeren birleştirme koşulunun birleştirmeden önce değil, sonra değerlendirilmesidir.

  • M2_1, HASHJOIN işlemini gerçekleştirir, ardından LT(total_price, total_price) filtresini (a.total_price < b.total_price koşulunu temsil eder) uygular ve kısmi toplama (Partial_1 aşaması) çalıştırır. Partial_1 aşaması, verileri map tarafında önceden toplayarak reduce görevine gönderilen veri hacmini azaltır.

  • R3_2, M2_1'den gelen kısmi sonuçları birleştirerek toplamayı Final aşamasında tamamlar. İki aşamalı (Partial_1 -> Final) yaklaşım, map tarafındaki veri hacmi büyük olduğunda 1. Örnekteki tek aşamalı Complete moduna göre daha verimlidir.

  • R4_3, 1. Örnekle aynı şekilde nihai çıktı sütunlarını seçer ve takma ad atar.