DELETE neden performans üzerinde kalıcı bir etki bırakıyor?


20

Sonunda, @table değişkeni ve #temp tablosu arasındaki performansı karşılaştırmak için bir test komut dosyası bulunur. Bence doğru şekilde kurdum - performans zamanlamaları dışarıda DELETE / TRUNCATE komutlarının . Aldığım sonuçlar aşağıdaki gibidir (milisaniye cinsinden zamanlar).

@Table Variable  #Temp (delete)  #Temp (truncate)
---------------  --------------  ----------------
5723             5180            5506
15636            14746           7800
14506            14300           5583
14030            15460           5386
16706            16186           5360

Sadece aklı başında olduğumdan emin olmak için, bu CURRENT_TIMESTAMP (aka GetDate()) ifadesinin toplu iş değil, alındığı anlamına gelir, bu nedenle TRUNCATE / DELETE ile SET @StartTime = CURRENT_TIMESTAMPifade arasında bir etkileşim olmamalıdır .

select current_timestamp
waitfor delay '00:00:04'
select current_timestamp

-----------------------
2012-10-21 11:29:20.290

-----------------------
2012-10-21 11:29:24.290

DELETE, tabloyu temizlemek için kullanıldığında, ilk çalıştırma ile sonraki çalıştırma arasındaki atlamada oldukça tutarlıdır. DELETE anlayışımda eksik olan ne ? Bunu birçok kez tekrarladım, siparişi değiştirdim, büyüme gerektirmeyecek büyüklükte tempdb.

CREATE TABLE #values (
  id int identity primary key, -- will be clustered
  name varchar(100) null,
  number int null,
  type char(3) not null,
  low int null,
  high int null,
  status smallint not null
);
GO
SET NOCOUNT ON;

DECLARE @values TABLE (
  id int identity primary key clustered,
  name varchar(100) null,
  number int null,
  type char(3) not null,
  low int null,
  high int null,
  status smallint not null
);
DECLARE  @ExecutionTime  TABLE(      Duration bigINT    ) 
DECLARE  @StartTime DATETIME,  @i INT = 1; 
WHILE (@i <= 5) 
  BEGIN 
    DELETE @values;
    DBCC freeproccache With NO_InfoMSGS;
    DBCC DROPCLEANBUFFERS With NO_InfoMSGS;
    SET @StartTime = CURRENT_TIMESTAMP -- alternate getdate() 
    /****************** measured process ***********************/ 

    INSERT @values SELECT a.* FROM master..spt_values a join master..spt_values b on b.type='P' and b.number < 1000;

    /**************** end measured process *********************/ 
    INSERT @ExecutionTime 
    SELECT DurationInMilliseconds = datediff(ms,@StartTime,CURRENT_TIMESTAMP) 
    SET @i +=  1 
  END -- WHILE 

SELECT DurationInMilliseconds = Duration FROM   @ExecutionTime 
GO 

-- Temporary table
DECLARE  @ExecutionTime  TABLE(      Duration bigINT    ) 
DECLARE  @StartTime DATETIME,  @i INT = 1; 
WHILE (@i <= 5) 
  BEGIN 
    delete #values;
    -- TRUNCATE TABLE #values;
    DBCC freeproccache With NO_InfoMSGS;
    DBCC DROPCLEANBUFFERS With NO_InfoMSGS;
    SET @StartTime = CURRENT_TIMESTAMP -- alternate getdate() 
    /****************** measured process ***********************/ 

    INSERT #values SELECT a.* FROM master..spt_values a join master..spt_values b on b.type='P' and b.number < 1000;

    /**************** end measured process *********************/ 
    INSERT @ExecutionTime 
    SELECT DurationInMilliseconds = datediff(ms,@StartTime,CURRENT_TIMESTAMP) 
    SET @i +=  1 
  END -- WHILE 

SELECT DurationInMilliseconds = Duration FROM   @ExecutionTime 
GO

DROP TABLE  #values 
SET NOCOUNT OFF;

Yanıtlar:


20

Bu fark sadece nesne bir B + ağacı olduğunda geçerlidir. primary keyTablo değişkeni kaldırırken bir yığın olduğu için aşağıdaki sonuçları aldım

2560
2120
2080
2130
2140

Ancak PK ile testlerimde benzer bir model buldum ve aşağıda tipik sonuçlar elde ettim.

+--------+--------+---------+-------------------+
| @table | #table | ##table | [permanent_table] |
+--------+--------+---------+-------------------+
|   2670 |   2683 |    9603 |              9703 |
|   6823 |   6840 |    9723 |              9790 |
|   6813 |   6816 |    9626 |              9703 |
|   6883 |   6816 |    9600 |              9716 |
|   6840 |   6856 |    9610 |              9673 |
+--------+--------+---------+-------------------+

Benim teorim, yerel geçici B + ağaçlarına toplu ekler yapılırken kullanılabilecek bazı optimizasyonların mevcut olmasıdır.

Bunu aşağıdaki gözlemlere dayandırıyorum.

  1. Test kodunuzun çeşitli sürümlerini çalıştırırken sadece bu tabloyu @table_variablesve #temptablolarıyla gördüm . Tablolarda tempdbveya ##tablolarda kalıcı tablolar değil .

  2. Daha yavaş performans elde etmek için, daha önce tabloya çok sayıda satır eklemeniz ve kaldırmanız gerekmez. Tek bir satır eklemek ve orada bırakmak yeterlidir.

  3. TRUNCATEtablodaki tüm sayfaları ayırır. DELETEtablodaki son sayfanın yeniden konumlandırılmasına neden olmaz.

  4. VS 2012 profili oluşturucusu kullanarak SQL Server'ın daha hızlı bir durumda farklı bir kod yolu kullandığını gösterir. Zamanın% 36'sı , daha yavaş dava için sqlmin.dll!RowsetBulk::InsertRowharcanan zamanın% 61'ine karşılık gelir sqlmin.dll!RowsetNewSS::InsertRow.

Koşu

SELECT * 
FROM sys.dm_db_index_physical_stats(2,OBJECT_ID('tempdb..#values'),1,NULL, 'DETAILED')

silme döndükten sonra

+-------------+------------+--------------+--------------------+
| index_level | page_count | record_count | ghost_record_count |
+-------------+------------+--------------+--------------------+
|           0 |          1 |            0 |                  1 |
|           1 |          1 |            1 |                  0 |
|           2 |          1 |            1 |                  0 |
+-------------+------------+--------------+--------------------+

İzleme bayrağı 610'u etkinleştirerek zaman tutarsızlığını bir şekilde azaltmanın mümkün olduğunu buldum .

Bu azaltma etkisine sahip miktar (artık tek tek takılı satır değerleri kaydeder olarak aşağı 350 MB 103 MB den) daha sonra uçlar için esas itibarıyla giriş arasında, ancak bu 2 ve sonraki için zamanlamaları sadece küçük bir iyileşme @table, #tablevakaların ve boşluk hala devam ediyor. İz bayrağı, diğer iki tablo türüne eklenen eklerin genel performansını önemli ölçüde geliştirdi.

+--------+--------+---------+-------------------+
| @table | #table | ##table | [permanent_table] |
+--------+--------+---------+-------------------+
|   2663 |   2670 |    5403 |              5426 |
|   5390 |   5396 |    5410 |              5403 |
|   5373 |   5390 |    5410 |              5403 |
|   5393 |   5410 |    5406 |              5433 |
|   5386 |   5396 |    5390 |              5420 |
+--------+--------+---------+-------------------+

İşlem günlüğüne baktığımda boş yerel geçici tablolara karşı ilk eklerin çok daha az günlük (96 MB'de) göründüğünü fark ettim.

Özellikle bu daha hızlı kesici uçlar , daha yavaş vakalardakine kıyasla sadece 657işlemlere ( LOP_BEGIN_XACT/ LOP_COMMIT_XACTçiftlere) sahipti 10,000. Özellikle LOP_FORMAT_PAGEoperasyonlar çok azalmış gibi görünüyor. Yavaş durumlarda, tablodaki her sayfa için (yaklaşık 10,270) yalnızca4 hızlı tür girişlerle .

Her üç durumda da kullanılan günlük şöyleydi (Metin miktarını azaltmak için sistem taban tablolarında yapılan güncellemeler için günlük kayıtlarını sildim, ancak yine de toplamlara dahil edildi)

İlk eki günlüğe kaydetme @table_var(96,5 MB)

+-----------------------+----------+----------------------------------------------+---------------+---------+
|       Operation       | Context  |                AllocUnitName                 | Size in Bytes |   Cnt   |
+-----------------------+----------+----------------------------------------------+---------------+---------+
| LOP_BEGIN_XACT        | LCX_NULL | NULL                                         |         83876 |     658 |
| LOP_COMMIT_XACT       | LCX_NULL | NULL                                         |         34164 |     657 |
| LOP_CREATE_ALLOCCHAIN | LCX_NULL | NULL                                         |           120 |       3 |
| LOP_FORMAT_PAGE       | LCX_HEAP | dbo.#531856C7                                |            84 |       1 |
| LOP_FORMAT_PAGE       | LCX_IAM  | dbo.#4F47C5E3.PK__#4F47C5E__3213E83F51300E55 |            84 |       1 |
| LOP_FORMAT_PAGE       | LCX_IAM  | dbo.#531856C7                                |            84 |       1 |
| LOP_FORMAT_PAGE       | LCX_IAM  | Unknown Alloc Unit                           |            84 |       1 |
| LOP_HOBT_DDL          | LCX_NULL | NULL                                         |           216 |       6 |
| LOP_HOBT_DELTA        | LCX_NULL | NULL                                         |           320 |       5 |
| LOP_IDENT_NEWVAL      | LCX_NULL | NULL                                         |     100240000 | 2506000 |
| LOP_INSERT_ROWS       | LCX_HEAP | dbo.#531856C7                                |            72 |       1 |
| LOP_MODIFY_ROW        | LCX_IAM  | dbo.#531856C7                                |            88 |       1 |
| LOP_MODIFY_ROW        | LCX_PFS  | dbo.#4F47C5E3.PK__#4F47C5E__3213E83F51300E55 |        158592 |    1848 |
| LOP_MODIFY_ROW        | LCX_PFS  | dbo.#531856C7                                |            80 |       1 |
| LOP_MODIFY_ROW        | LCX_PFS  | Unknown Alloc Unit                           |        216016 |    2455 |
| LOP_SET_BITS          | LCX_GAM  | dbo.#4F47C5E3.PK__#4F47C5E__3213E83F51300E55 |         84360 |    1406 |
| LOP_SET_BITS          | LCX_GAM  | Unknown Alloc Unit                           |        147120 |    2452 |
| LOP_SET_BITS          | LCX_IAM  | dbo.#4F47C5E3.PK__#4F47C5E__3213E83F51300E55 |         84360 |    1406 |
| LOP_SET_BITS          | LCX_IAM  | Unknown Alloc Unit                           |        147120 |    2452 |
| Total                 | NULL     | NULL                                         |     101209792 | 2519475 |
+-----------------------+----------+----------------------------------------------+---------------+---------+

Sonraki insertlerin kaydedilmesi TF 610 kapalı (350 MB)

+-----------------------+--------------------+----------------------------------------------+---------------+---------+
|       Operation       |      Context       |                AllocUnitName                 | Size in Bytes |   Cnt   |
+-----------------------+--------------------+----------------------------------------------+---------------+---------+
| LOP_BEGIN_CKPT        | LCX_NULL           | NULL                                         |            96 |       1 |
| LOP_BEGIN_XACT        | LCX_NULL           | NULL                                         |       1520696 |   12521 |
| LOP_COMMIT_XACT       | LCX_NULL           | NULL                                         |        651040 |   12520 |
| LOP_CREATE_ALLOCCHAIN | LCX_NULL           | NULL                                         |            40 |       1 |
| LOP_DELETE_SPLIT      | LCX_INDEX_INTERIOR | dbo.#4F47C5E3.PK__#4F47C5E__3213E83F51300E55 |          2160 |      36 |
| LOP_END_CKPT          | LCX_NULL           | NULL                                         |           136 |       1 |
| LOP_FORMAT_PAGE       | LCX_HEAP           | dbo.#4F47C5E3.PK__#4F47C5E__3213E83F51300E55 |        859236 |   10229 |
| LOP_FORMAT_PAGE       | LCX_IAM            | Unknown Alloc Unit                           |            84 |       1 |
| LOP_FORMAT_PAGE       | LCX_INDEX_INTERIOR | dbo.#4F47C5E3.PK__#4F47C5E__3213E83F51300E55 |          3108 |      37 |
| LOP_HOBT_DDL          | LCX_NULL           | NULL                                         |           648 |      18 |
| LOP_HOBT_DELTA        | LCX_NULL           | NULL                                         |        657088 |   10267 |
| LOP_IDENT_NEWVAL      | LCX_NULL           | NULL                                         |     100239960 | 2505999 |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | dbo.#4F47C5E3.PK__#4F47C5E__3213E83F51300E55 |     258628000 | 2506000 |
| LOP_INSERT_ROWS       | LCX_HEAP           | dbo.#531856C7                                |            72 |       1 |
| LOP_INSERT_ROWS       | LCX_INDEX_INTERIOR | dbo.#4F47C5E3.PK__#4F47C5E__3213E83F51300E55 |       1042776 |   10302 |
| LOP_MODIFY_HEADER     | LCX_HEAP           | dbo.#4F47C5E3.PK__#4F47C5E__3213E83F51300E55 |        859236 |   10229 |
| LOP_MODIFY_HEADER     | LCX_INDEX_INTERIOR | dbo.#4F47C5E3.PK__#4F47C5E__3213E83F51300E55 |          3192 |      38 |
| LOP_MODIFY_ROW        | LCX_IAM            | dbo.#4F47C5E3.PK__#4F47C5E__3213E83F51300E55 |           704 |       8 |
| LOP_MODIFY_ROW        | LCX_PFS            | dbo.#4F47C5E3.PK__#4F47C5E__3213E83F51300E55 |        934264 |   11550 |
| LOP_MODIFY_ROW        | LCX_PFS            | Unknown Alloc Unit                           |        783984 |    8909 |
| LOP_SET_BITS          | LCX_GAM            | dbo.#4F47C5E3.PK__#4F47C5E__3213E83F51300E55 |         76980 |    1283 |
| LOP_SET_BITS          | LCX_GAM            | Unknown Alloc Unit                           |        534480 |    8908 |
| LOP_SET_BITS          | LCX_IAM            | dbo.#4F47C5E3.PK__#4F47C5E__3213E83F51300E55 |         76980 |    1283 |
| LOP_SET_BITS          | LCX_IAM            | Unknown Alloc Unit                           |        534480 |    8908 |
| LOP_SHRINK_NOOP       | LCX_NULL           | NULL                                         |            32 |       1 |
| LOP_XACT_CKPT         | LCX_NULL           | NULL                                         |            92 |       1 |
| Total                 | NULL               | NULL                                         |     367438748 | 5119297 |
+-----------------------+--------------------+----------------------------------------------+---------------+---------+

Sonraki insertlerin kaydedilmesi TF 610 (103 MB)

+-------------------------+-------------------------+----------------------------------------------+---------------+---------+
|        Operation        |         Context         |                AllocUnitName                 | Size in Bytes |   Cnt   |
+-------------------------+-------------------------+----------------------------------------------+---------------+---------+
| LOP_BEGIN_CKPT          | LCX_NULL                | NULL                                         |           192 |       2 |
| LOP_BEGIN_XACT          | LCX_NULL                | NULL                                         |       1339796 |   11099 |
| LOP_BULK_EXT_ALLOCATION | LCX_NULL                | NULL                                         |         20616 |     162 |
| LOP_COMMIT_XACT         | LCX_NULL                | NULL                                         |        577096 |   11098 |
| LOP_CREATE_ALLOCCHAIN   | LCX_NULL                | NULL                                         |            40 |       1 |
| LOP_DELETE_SPLIT        | LCX_INDEX_INTERIOR      | dbo.#6DCC4D03.PK__#6DCC4D0__3213E83F6FB49575 |          2160 |      36 |
| LOP_END_CKPT            | LCX_NULL                | NULL                                         |           272 |       2 |
| LOP_FORMAT_PAGE         | LCX_BULK_OPERATION_PAGE | dbo.#6DCC4D03.PK__#6DCC4D0__3213E83F6FB49575 |        863520 |   10280 |
| LOP_FORMAT_PAGE         | LCX_IAM                 | Unknown Alloc Unit                           |            84 |       1 |
| LOP_FORMAT_PAGE         | LCX_INDEX_INTERIOR      | dbo.#6DCC4D03.PK__#6DCC4D0__3213E83F6FB49575 |          3108 |      37 |
| LOP_HOBT_DELTA          | LCX_NULL                | NULL                                         |        666496 |   10414 |
| LOP_IDENT_NEWVAL        | LCX_NULL                | NULL                                         |     100239960 | 2505999 |
| LOP_INSERT_ROWS         | LCX_CLUSTERED           | dbo.#6DCC4D03.PK__#6DCC4D0__3213E83F6FB49575 |         23544 |     218 |
| LOP_INSERT_ROWS         | LCX_HEAP                | dbo.#719CDDE7                                |            72 |       1 |
| LOP_INSERT_ROWS         | LCX_INDEX_INTERIOR      | dbo.#6DCC4D03.PK__#6DCC4D0__3213E83F6FB49575 |       1042776 |   10302 |
| LOP_MODIFY_HEADER       | LCX_BULK_OPERATION_PAGE | dbo.#6DCC4D03.PK__#6DCC4D0__3213E83F6FB49575 |        780216 |   10266 |
| LOP_MODIFY_HEADER       | LCX_HEAP                | dbo.#6DCC4D03.PK__#6DCC4D0__3213E83F6FB49575 |       1718472 |   20458 |
| LOP_MODIFY_HEADER       | LCX_INDEX_INTERIOR      | dbo.#6DCC4D03.PK__#6DCC4D0__3213E83F6FB49575 |          3192 |      38 |
| LOP_MODIFY_ROW          | LCX_IAM                 | dbo.#6DCC4D03.PK__#6DCC4D0__3213E83F6FB49575 |           704 |       8 |
| LOP_MODIFY_ROW          | LCX_PFS                 | dbo.#6DCC4D03.PK__#6DCC4D0__3213E83F6FB49575 |        114832 |    1307 |
| LOP_MODIFY_ROW          | LCX_PFS                 | Unknown Alloc Unit                           |        231696 |    2633 |
| LOP_RANGE_INSERT        | LCX_NULL                | NULL                                         |            48 |       1 |
| LOP_SET_BITS            | LCX_GAM                 | dbo.#6DCC4D03.PK__#6DCC4D0__3213E83F6FB49575 |         77100 |    1285 |
| LOP_SET_BITS            | LCX_GAM                 | Unknown Alloc Unit                           |        157920 |    2632 |
| LOP_SET_BITS            | LCX_IAM                 | dbo.#6DCC4D03.PK__#6DCC4D0__3213E83F6FB49575 |         77100 |    1285 |
| LOP_SET_BITS            | LCX_IAM                 | Unknown Alloc Unit                           |        157920 |    2632 |
| LOP_XACT_CKPT           | LCX_NULL                | NULL                                         |            92 |       1 |
| Total                   | NULL                    | NULL                                         |     108102960 | 2602218 |
+-------------------------+-------------------------+----------------------------------------------+---------------+---------+

Ayrıntılı onay için teşekkürler. Yani soru hala devam ediyor, DELETE neden teriminizi kullanarak tabloyu gerçekten boş bırakmıyor . Ayrıca, toplu işleme döngüsünde sil / doldur komutu kullanılıyorsa #temp tablolarını kullanmak için bu durum tartışılır.
孔夫子

1
@RichardTheKiwi - Kendi başına TRUNCATEdevralmanın yararı DELETEda bunun için tartışmalıdır. Ayrıca nadiren çok sayıda satır için tablo değişkenleri düşünün.
Martin Smith

Bu tembel görünecek, ancak bir partide 1000 kez 1 ila 10 kayıt (değişken) eki tekrarlamak aynı semptomları gösteriyor mu? Çok sayıda satır kullanımı yalnızca sorunu daha da kötüleştirmek ve farkı daha iyi görmek için ölçek sağlamaktır. Sorunun özü, farkın ne olduğunu bildiğimizde #temp tablolarının daha iyi olacağını bir şekilde kanıtlamaktır.
孔夫子

Benim teorim 10,000+çok daha optimize bir şekilde gerçekleşir ve sayfa başına yükü bazı önlemek gibi görünüyor sayfaların tahsis olmasıdır . Daha küçük kesici uçlar için böyle bir farkın daha az anlamlı olmasını beklerim.
Martin Smith

@RichardTheKiwi - Teşekkürler! Muhtemelen bu konuda söylenecek daha çok şey var. SQL Kiwi ile aynı sürüme yükseltmeyi ve hala farklı kod yollarını görüp görmediğimi görmeyi deneyeceğim. Eğer öyleyse, belki de böyle bir fark yaratması donanıma bağlıdır (testlerim aynı SSD'deki tüm veriler ve günlük dosyaları ile masaüstü bilgisayarımda yapıldı)
Martin Smith

0

Gözlem ve spekülasyon. . .

Bazı sistemlerde, CURRENT_TIMESTAMP geçerli işlemin başlangıcındaki saat olarak tanımlanır. Hızlı bir arama, CURRENT_TIMESTAMP'in SQL Server'da nasıl davrandığına dair kesin bir belge ortaya koymadı. Ancak SQL Server'ın varsayılan modu işlemleri otomatik olarak tamamlamaktır ve burada BEGIN TRANSACTION yoktur, bu yüzden gerekir INSERT deyimi hemen önce zaman olmaktır. (DELETE deyimi otomatik olarak yürütülmelidir ve CURRENT_TIMESTAMP SQL Server'da hangi şekilde çalışırsa çalışsın, otomatik olarak işlenen işlemleri kullandığınızda DELETE deyimi ile bir ilgisi olmamalıdır.)

İlk yinelemede, DELETE deyiminin yapacak gerçek bir işi yoktur ve günlüğe kaydedilecek tek bir satır yoktur. Belki optimizer bunu bilir ve bu da ilk yineleme süresini azaltır. (Silinecek satır ve günlüğe kaydedilecek tek satırın birleşimi.)

Silmeden önce ekleyerek (bence) bunu test edebilirsiniz.


Bugün soruları yanıtlamayı bırakacağım. Ya da o kutuya bir şeyler yazdığımda ne yaparsam yapayım.
Mike Sherrill 'Cat Recall'

Bu cevap eski, teğet ve dikkat dağıtıcı olarak mı silinmeli?
孔夫子
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.