Paralel planda yanlış 'Gerçek' satır sayıları


17

Bu tamamen akademik bir sorudur, o kadar ki bir soruna neden olmaz ve sadece davranışla ilgili herhangi bir açıklama duymak isterim.

Standart bir sorun alın Itzik Ben-Gan CTE taksitli hesap tablosu

USE [master]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE FUNCTION [dbo].[TallyTable] 
(   
    @N INT
)
RETURNS TABLE WITH SCHEMABINDING AS
RETURN 
(
    WITH 
    E1(N) AS 
    (
        SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
        SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
        SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
    )                                       -- 1*10^1 or 10 rows
    , E2(N) AS (SELECT 1 FROM E1 a, E1 b)   -- 1*10^2 or 100 rows
    , E4(N) AS (SELECT 1 FROM E2 a, E2 b)   -- 1*10^4 or 10,000 rows
    , E8(N) AS (SELECT 1 FROM E4 a, E4 b)   -- 1*10^8 or 100,000,000 rows

    SELECT TOP (@N) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS N FROM E8 
)
GO

1 milyon satır sayısı tablosu oluşturacak bir sorgu düzenleyin:

SELECT
    COUNT(N)
FROM
    dbo.TallyTable(1000000) tt

Bu sorgu için paralel yürütme planına göz atın:

Paralel yürütme planı

Toplama akışları işlecinden önceki 'gerçek' satır sayısının 1.004.588 olduğunu unutmayın. Toplama akışları operatöründen sonra satır sayısı beklenen 1.000.000 olur. Yine de, değer tutarlı değil ve çalışmadan çalışmaya değişir. COUNT öğesinin sonucu her zaman doğrudur.

Paralel olmayan planı zorlayarak sorguyu yeniden yayınlayın:

SELECT
    COUNT(N)
FROM
    dbo.TallyTable(1000000) tt
OPTION (MAXDOP 1)

Bu sefer tüm operatörler doğru 'gerçek' satır sayısını gösterir.

Paralel olmayan yürütme planı

Bunu 2005SP3 ve 2008R2'de denedim, her ikisinde de aynı sonuçlar. Buna neyin sebep olabileceğine dair düşünceleriniz var mı?

Yanıtlar:


12

Satırlar, bir seferde bir satır yerine, üreticiden paketlerdeki tüketici iş parçacığına (dolayısıyla CXPACKET - sınıf değişim paketi) aktarılır. Borsada belirli miktarda tamponlama var. Ayrıca, boru hattını Gather Streams'in tüketici tarafından kapatma çağrısı, bir kontrol paketinde üretici iş parçacıklarına iletilmelidir. Programlama ve diğer dahili hususlar, paralel planların her zaman belirli bir 'durma mesafesine' sahip olduğu anlamına gelir.

Sonuç olarak, genellikle bir alt ağacın tüm potansiyel satır kümesinden daha azının gerekli olduğu bu tür satır sayısı farkını görürsünüz. Bu durumda, TOP yürütmeyi 'erken sona' getirir.

Daha fazla bilgi:


10

Sanırım bunun için kısmi bir açıklama yapabilirim ama lütfen onu vurmaktan veya alternatifler göndermekten çekinmeyin. @MartinSmith, yürütme planında TOP'un etkisini vurgulayarak kesinlikle bir şeye bağlıdır.

Basitçe söylemek gerekirse, 'Gerçek Satır Sayısı' bir operatörün işlediği satırların sayısı değil, operatörün GetNext () yönteminin kaç kez çağrıldığıdır.

Alındığı BOL :

Fiziksel operatörler başlatılır, veri toplar ve kapanır. Özellikle, fiziksel operatör aşağıdaki üç yöntem çağrısına cevap verebilir:

  • Init (): Init () yöntemi, fiziksel bir operatörün kendisini başlatmasına ve gerekli veri yapılarını ayarlamasına neden olur. Fiziksel işleç birçok Init () çağrısı alabilir, ancak fiziksel bir işleç yalnızca bir tanesini alır.
  • GetNext (): GetNext () yöntemi, fiziksel bir operatörün ilk veya sonraki veri satırını almasına neden olur. Fiziksel işleç sıfır veya çok sayıda GetNext () çağrısı alabilir.
  • Close (): Close () yöntemi, fiziksel bir operatörün bazı temizleme işlemleri gerçekleştirmesine ve kendini kapatmasına neden olur. Fiziksel bir operatör yalnızca bir Close () çağrısı alır.

GetNext () yöntemi bir veri satırı döndürür ve çağrılma sayısı SET STATISTICS PROFILE ON veya SET STATISTICS XML ON kullanılarak üretilen Showplan çıktısında ActualRows olarak görünür.

Tamlık uğruna, paralel operatörler üzerinde küçük bir arka plan yararlıdır. İş, yeniden bölümleme akışı veya dağıtım akışı operatörleri tarafından paralel bir plandaki birden fazla akışa dağıtılır. Bunlar, dört mekanizmadan birini kullanarak satırları veya sayfaları iş parçacıkları arasında dağıtır:

  • Hash, satırları, satırdaki sütunların karmasını temel alarak dağıtır
  • Round-robin , bir döngüdeki iş parçacığı listesinde yineleme yaparak satırları dağıtır
  • Yayın tüm sayfaları veya satırları tüm dizilere dağıtır
  • Talep bölümleme sadece taramalar için kullanılır. İş parçacıkları döner, operatörden bir veri sayfası ister, işler ve tamamlandığında başka bir sayfa ister.

İlk dağıtım akışı operatörü (planın en sağında), sabit bir taramadan kaynaklanan satırlarda talep bölümleme kullanır. Toplam 10 'Gerçek Satır' için GetNext () 6, 4 ve 0 kez çağıran üç iş parçacığı vardır:

<RunTimeInformation>
       <RunTimeCountersPerThread Thread="2" ActualRows="6" ActualEndOfScans="1" ActualExecutions="1" />
       <RunTimeCountersPerThread Thread="1" ActualRows="4" ActualEndOfScans="1" ActualExecutions="1" />
       <RunTimeCountersPerThread Thread="0" ActualRows="0" ActualEndOfScans="0" ActualExecutions="0" />
 </RunTimeInformation>

Bir sonraki dağıtım operatörünün tekrar üç iş parçacığı var, bu sefer GetNext () 'e 50, 50 ve 0 çağrı ile toplam 100

<RunTimeInformation>
    <RunTimeCountersPerThread Thread="2" ActualRows="50" ActualEndOfScans="1" ActualExecutions="1" />
    <RunTimeCountersPerThread Thread="1" ActualRows="50" ActualEndOfScans="1" ActualExecutions="1" />
    <RunTimeCountersPerThread Thread="0" ActualRows="0" ActualEndOfScans="0" ActualExecutions="0" />
</RunTimeInformation>

Nedeni ve açıklaması muhtemelen bir sonraki paralel operatörde belirir.

<RunTimeInformation>
    <RunTimeCountersPerThread Thread="2" ActualRows="1" ActualEndOfScans="0" ActualExecutions="1" />
    <RunTimeCountersPerThread Thread="1" ActualRows="10" ActualEndOfScans="0" ActualExecutions="1" />
    <RunTimeCountersPerThread Thread="0" ActualRows="0" ActualEndOfScans="0" ActualExecutions="0" />
</RunTimeInformation>

Şimdi GetNext'e () 10 çağrı yapmayı beklediğimiz 11 çağrı var.

Düzenleme: 2011-11-13

Bu noktada sıkışmış, ben de ahbap ile cevapları hawking gitti kümelenmiş indeksi ve @MikeWalsh nazik yönettiği @SQLKiwi burada .


7

1,004,588 testlerimde de çok fazla değer veren bir figür.

Bunu aşağıda biraz daha basit bir plan için de görüyorum.

WITH 
E1(N) AS 
(
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)                                       -- 1*10^1 or 10 rows
, E2(N) AS (SELECT 1 FROM E1 a, E1 b)   -- 1*10^2 or 100 rows
, E4(N) AS (SELECT 1 FROM E2 a, E2 b)   -- 1*10^4 or 10,000 rows
SELECT * INTO #E4 FROM E4;

WITH E8(N) AS (SELECT 1 FROM #E4 a, #E4 b),
Nums(N) AS (SELECT  TOP (1000000) ROW_NUMBER() OVER (ORDER BY (SELECT 0)) FROM E8 )
SELECT COUNT(N) FROM Nums

DROP TABLE #E4

Plan

İcra planına diğer ilgi alanları:

+----------------------------------+--------------+--------------+-----------------+
|                                  | Table Scan A | Table Scan B | Row Count Spool |
+----------------------------------+--------------+--------------+-----------------+
| Number Of Executions             | 2            |            2 |             101 |
| Actual Number Of Rows - Total    | 101          |        20000 |         1004588 |
| Actual Number Of Rows - Thread 0 | -            |              |                 |
| Actual Number Of Rows - Thread 1 | 95           |        10000 |          945253 |
| Actual Number Of Rows - Thread 2 | 6            |        10000 |           59335 |
| Actual Rebinds                   | 0            |            0 |               2 |
| Actual Rewinds                   | 0            |            0 |              99 |
+----------------------------------+--------------+--------------+-----------------+

Benim tahminime göre, görevler paralel olarak işleniyor çünkü bir görev orta uçuş işleme satırlarında, diğeri toplama akışları operatörüne milyonuncu satırı iletirken ek satırlar işleniyor. Ayrıca bu makaleden satırlar bu yineleyiciye toplu olarak arabelleğe alınır ve dağıtılır, bu nedenle işlenen satır sayısının tam olarakTOP herhangi bir olayda .

Düzenle

Sadece buna biraz daha ayrıntılı bakıyorum. Ben sadece 1,004,588yukarıda belirtilen satır sayısı daha çok 1000 yineleme için bir döngüde yukarıdaki sorgu koştu ve gerçek yürütme planları yakaladı daha çeşitli alıyordu fark ettim . Paralellik derecesinin sıfır olduğu 81 sonucun atılması, aşağıdaki rakamları vermiştir.

count       Table Scan A: Total Actual Row Spool - Total Actual Rows
----------- ------------------------------ ------------------------------
352         101                            1004588
323         102                            1004588
72          101                            1003565
37          101                            1002542
35          102                            1003565
29          101                            1001519
18          101                            1000496
13          102                            1002542
5           9964                           99634323
5           102                            1001519
4           9963                           99628185
3           10000                          100000000
3           9965                           99642507
2           9964                           99633300
2           9966                           99658875
2           9965                           99641484
1           9984                           99837989
1           102                            1000496
1           9964                           99637392
1           9968                           99671151
1           9966                           99656829
1           9972                           99714117
1           9963                           99629208
1           9985                           99847196
1           9967                           99665013
1           9965                           99644553
1           9963                           99623626
1           9965                           99647622
1           9966                           99654783
1           9963                           99625116

1.004.588'in en yaygın sonuç olduğu görülebilir, ancak 3 durumda mümkün olan en kötü durum meydana geldi ve 100.000.000 satır işlendi. Gözlenen en iyi vaka 19 kez meydana gelen 1.000.496 satır sayısı idi.

Çoğaltmak için Tam komut dosyası bu cevabın 2. düzeltmesinin altındadır (2'den fazla işlemciye sahip bir sistemde çalıştırılırsa ince ayar yapılması gerekir).


1

Sorunun, satırların akışlar arasında nasıl oyulduğuna bağlı olarak birden çok akışın aynı satırı işleyebileceğinden kaynaklandığına inanıyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.