Tüm Ürünler
Search
Belge Merkezi

MaxCompute:SQL sorgu optimizasyonu

Son Güncelleme:Oct 04, 2026

MaxCompute'deki SQL sorgunuz yavaş çalışıyorsa kök neden genellikle SQL mantığı değil iş yükünün dağıtım biçimidir. Yanlış yapılandırılan paralellik derecesi (DOP) yani işinizi yürüten paralel örnek sayısı ciddi performans darboğazlarına yol açar. Bu durum tüm verilerin tek bir çalışan düğüme yığılarak performansı düşürmesine veya küçük bir görev için çok fazla örneğin başlatılması nedeniyle uzun kuyruk bekleme süreleri ve aşırı ek yüke neden olabilir. Bu kılavuz belirli iş yükünüz için DOP değerini teşhis etmek ve ayarlamak üzere pratik teknikler sunar. DOP değerini veri ve sorgu yapınızla doğru şekilde eşleştirerek yürütme hızını büyük ölçüde artırabilir ve kaynak kullanımını optimize edebilirsiniz.

Paralellik derecesi (DOP) optimizasyonu

Paralellik derecesi (DOP) bir işi kaç paralel örneğin çalıştırdığını gösterir. Örneğin kimliği M1 olan bir görev 1.000 örnek kullanıyorsa M1'in DOP değeri 1000 olur. DOP değerini uygun şekilde yapılandırmak iş yürütme verimliliğini önemli ölçüde artırır.

Aşağıdaki bölümlerde yaygın DOP optimizasyon senaryolarını açıklıyoruz.

Yürütme için tek bir örnek zorlama

Belirli işlemler bir işi tek bir örneğe zorlar bu da tüm paralelliği ortadan kaldırarak ciddi bir darboğaz yaratır. Bu işlemler şunları içerir:

  • GROUP BY yan tümcesi olmadan veya bir sabit üzerinde GROUP BY yan tümcesi ile toplama yapma.

  • OVER yan tümcesinin bir sabiti PARTITION BY olarak belirttiği bir pencere fonksiyonu kullanma. PARTITION BY ifadesini tamamen atlamak da aynı etkiyi yaratır çünkü tüm veriler tek bir örnekte sıralanır ve toplanır.

  • Bir sabit üzerinde DISTRIBUTE BY veya CLUSTER BY yan tümcesi kullanma.

Bu darboğazdan kaçınmak için küresel toplamaya gereksinim duyup duymadığınızı gözden geçirin. Gerekliyse iki aşamalı toplama deseni kullanın: önce yüksek kardinaliteli bir anahtara göre gruplayarak kısmi toplamayı tüm örneklerde paralel olarak çalıştırın ardından nihai toplamayı çok daha küçük olan ara sonuç kümesi üzerinde yapın.

Hatalı örnek sayısının etkisi

Önemli

Yüksek paralellik her zaman daha iyi performans anlamına gelmez. Çok fazla örnek kullanmak yürütmeyi iki nedenle yavaşlatır:

  • Aşırı paralellik kaynak çekişmesini ve kuyruk bekleme sürelerini artırır.

  • Her örneğin bir başlatma aşaması vardır. Yüksek DOP değerlerinde kümülatif başlatma ek yükü gerçek hesaplama için ayrılan süreyi azaltır.

Aşağıdaki senaryolar yaygın olarak suboptimal bir örnek sayısına neden olur:

  • Çok sayıda küçük bölüm okuma: Bir sorgu 10.000 bölümü tararsa sistem 10.000 örnek başlatabilir. Her örnek milisaniyeler içinde tamamlanır ancak bu sürenin çoğunu kuyrukta bekleyerek geçirir.

    Sorgunun erken aşamalarında etkili bölüm budama uygulayarak gereksiz bölümleri filtreleyin veya sorguyu daha küçük hedefe yönelik işlere bölerek bölüm tarama sayısını azaltın.

  • Küçük bir mapper bölme boyutu: Varsayılan 256 MB bölme boyutu büyük giriş veri kümelerini birçok küçük örneğe böler. Her örnek yalnızca kısa bir süre çalışır ve bu sürenin çoğu hesaplama yerine kaynak kuyruğunda beklemekle geçer.

    Her mapper örneğinin daha fazla veri işlemesi için bölme boyutunu artırın. Reducer örnek sayısını açıkça da ayarlayabilirsiniz.

    SET odps.stage.mapper.split.size=<256>;
    SET odps.stage.reducer.num=<Maximum number of concurrent instances>;

Örnek sayısını yapılandırma

  • Tablo okuma görevleri (mapper'lar) için

    • Yöntem 1: Genel bir bölme boyutu parametresi ayarlama.

      -- Configure the maximum amount of input data per mapper instance. Unit: MB.
      -- Default value: 256. Valid values: [1,Integer.MAX_VALUE].
      SET odps.sql.mapper.split.size=<value>;
    • Yöntem 2: Tablo başına kontrol için sorgu ipucu kullanma. split_size ipucu genel parametreyi belirli bir tablo okuma işlemi için geçersiz kılar ve sorgunun geri kalanını etkilemeden daha ince ayarlı kontrol sağlar.

      -- Split the src table into subtasks of 1 MB each.
      SELECT a.key FROM src a /*+split_size(1)*/ JOIN src2 b ON a.key=b.key;
    • Yöntem 3: Verileri tablo düzeyinde boyuta satır sayısına veya belirtilen bir DOP'a göre bölme.

    odps.sql.mapper.split.size parametresi tüm mapper aşamalarına genel olarak uygulanır ve minimum değeri 1 MB'dır. Satırların küçük olduğu ancak hesaplama açısından pahalı olduğu durumlar için yani bölme başına veri hacmini değiştirmeden daha fazla örnek istediğiniz durumlarda bunun yerine aşağıdaki tablo düzeyindeki parametreleri kullanın.

    Tablo düzeyinde DOP ayarı yapmak için aşağıdaki parametreleri kullanın:

    • Tablo düzeyinde örnek başına veri bölme boyutunu ayarlama.

      SET odps.sql.split.size = {"table1": 1024, "table2": 512};
    • Tablo düzeyinde örnek başına işlenen satır sayısını ayarlama.

      SET odps.sql.split.row.count = {"table1": 100, "table2": 500};
    • DOP'u doğrudan tablo düzeyinde ayarlama.

      SET odps.sql.split.dop = {"table1": 1, "table2": 5};
    Not

    odps.sql.split.row.count ve odps.sql.split.dop parametreleri yalnızca dahili tablolar işlem dışı tablolar ve kümelendirilmemiş tablolar için geçerlidir.

  • Okuma dışı görevler (reducer'lar ve joiner'lar) için

    • Yöntem 1: Reducer örnek sayısını ayarlama. Bu ayar sorgudaki tüm reducer görevlerine uygulanır.

      -- Set the number of reducer instances.
      -- Valid values: [1,99999].
      SET odps.stage.reducer.num=<value>;
    • Yöntem 2: Joiner örnek sayısını ayarlama. Bu ayar sorgudaki tüm joiner görevlerine uygulanır.

      -- Set the number of joiner instances.
      -- Valid values: [1,99999].
      SET odps.stage.joiner.num=<value>;
    • Yöntem 3: Yukarı akış mapper sayısını ayarlama. Reducer örnek sayısı kendinden önce gelen mapper aşamasından türetilir. Mapper sayısını artırmak reducer paralelliğini dolaylı olarak artırır.

Pencere fonksiyonu optimizasyonu

Bir sorgudaki her pencere fonksiyonu genellikle ayrı bir reduce işini tetikler. Bir sorgu birden fazla pencere fonksiyonu içerdiğinde bu durum kaynak tüketimini önemli ölçüde artırır. MaxCompute aşağıdaki iki koşulun da karşılanması durumunda birden fazla pencere fonksiyonunu otomatik olarak tek bir reduce işinde birleştirir:

  • OVER yan tümceleri aynıdır yani aynı PARTITION BY ve ORDER BY koşullarını içerir.

  • Pencere fonksiyonları aynı SELECT ifadesinde yer alır.

Aşağıdaki sorguda hem RANK() hem de ROW_NUMBER() fonksiyonları aynı OVER yan tümcesini paylaşır ve aynı SELECT ifadesinde görünür bu nedenle otomatik birleşmeye uygundur. MaxCompute bunları iki ayrı iş yerine tek bir reduce işinde çalıştırır.

SELECT
RANK() OVER (PARTITION BY A ORDER BY B desc) AS RANK,
ROW_NUMBER() OVER (PARTITION BY A ORDER BY B desc) AS row_num
FROM MyTable;

Alt sorgu optimizasyonu

Bir IN alt sorgusu kullanarak filtreleme yapan bir sorguyu ele alalım:

SELECT * FROM table_a a WHERE a.col1 IN (SELECT col1 FROM table_b b WHERE xxx);

Eğer table_b üzerindeki alt sorgu col1 için 9.999'dan fazla değer döndürürse MaxCompute şu hatayı bildirir: records returned from subquery exceeded limit of 9999. Bu sınırı kaldırmak için sorguyu bir JOIN olarak yeniden yazın:

SELECT a.* FROM table_a a JOIN (SELECT DISTINCT col1 FROM table_b b WHERE xxx) c ON (a.col1 = c.col1);
Not
  • DISTINCT ifadesini atlarsanız alt sorgu c içinden gelen yinelenen col1 değerleri a tablosundaki satırları çoğaltır ve beklenenden daha fazla sonuç üretir.

  • DISTINCT ifadesi alt sorguyu tek bir reducer'a zorlar bu durum büyük veri kümeleri için bir darboğaz haline gelir.

  • İş mantığınız col1 değerlerinin benzersiz olduğunu garanti ediyorsa tek reducer darboğazından kaçınmak için DISTINCT ifadesini kaldırın.

JOIN ifadesi optimizasyonu

MaxCompute'un bir JOIN sırasında bölüm budama uygulayabilmesi için bölümlenmiş tabloları join işlemi gerçekleşmeden önce filtreleyin sonrasında değil. Erken filtreleme yapılmazsa sistem önce tüm bölümler üzerinde JOIN işlemini gerçekleştirir ardından filtreyi uygular bu da gerekenden çok daha fazla verinin taranmasına neden olur.

Şu kuralları izleyin:

  • JOIN işleminden önce bir alt sorgu içinde ana tablo üzerinde bölüm sınırlama koşullarını uygulayın.

  • Ana tabloyu filtreleyen diğer WHERE yan tümcelerini SQL ifadesinin sonuna yerleştirin.

  • İkincil tablo üzerindeki bölüm sınırlama koşullarını ON yan tümcesinde veya bir alt sorguda uygulayın nihai WHERE yan tümcesinde değil.

Aşağıdaki örnekler bu uygulamaları göstermektedir.

SELECT * FROM A JOIN (SELECT * FROM B WHERE dt=20150301)B ON B.id=A.id WHERE A.dt=20150301;
SELECT * FROM A JOIN B ON B.id=A.id WHERE B.dt=20150301; -- We recommend that you do not use this statement. The system performs the JOIN operation before it performs partition pruning. This increases the amount of data and causes the query performance to deteriorate. 
SELECT * FROM (SELECT * FROM A WHERE dt=20150301)A JOIN (SELECT * FROM B WHERE dt=20150301)B ON B.id=A.id;

Toplama fonksiyonu optimizasyonu

Dize toplama işlemleri için wm_concat genellikle collect_list fonksiyonundan daha iyi performans gösterir. Aşağıdaki örnekler her iki fonksiyon kullanılarak yapılan eşdeğer işlemleri göstermektedir.

-- Implement the collect_list function.
SELECT concat_ws(',', sort_array(collect_list(key))) FROM src;
-- Implement the wm_concat function for better performance.
SELECT wm_concat(',', key) WITHIN GROUP (ORDER BY key) FROM src;

-- Implement the collect_list function.
SELECT array_join(collect_list(key), ',') FROM src;
-- Implement the wm_concat function for better performance.
SELECT wm_concat(',', key) FROM src;