TDS and Network packet size

Vi siete mai chiesti qual’e’ l’overhead del protocollo TDS? Il protocollo e’ ben documentato a questo indirizzo: http://msdn.microsoft.com/en-us/library/dd304523(v=PROT.13).aspx, tuttavia in questo post seguiremo un approccio differente da quello accademico: snifferemo i pacchetti (TCP) fra Management Studio e SQL Server per analizzarli ex-post. In questo modo avremo un pretesto per analizzare il comportamento del protocollo TDS.

Strumenti

Per la nostra analisi utilizzeremo Microsoft Network Monitor (per gli amici, NetMon) disponibile qui: http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=4865. Tramite NetMon e’ possibile intercettare tutti i pacchetti in ingresso ed in uscita da una interfaccia di rete.

Configurazione iniziale

Scriviamo un codice TSQL abbastanza prolisso da essere di dimensioni significative. Nel mio caso mi sono affidato al comment per ingrossare la dimensione del file.

Salviamo il codice dentro un file. Importante: assicuratevi che il formato sia ANSI (cfr 2.2.1.3 SQL Batch) altrimenti avrete dei numeri errati. Guardate la dimensione del file (proprieta’) per avere la dimensione del “payload utile” che invieremo a SQL Server:

La dimensione che ci interessa e’ il campo Size (non Size on disk). Nell’esempio il mio codice occupa 6.145 bytes. Essendo ANSI dobbiamo moltiplicare per 2 il numero di bytes occupati per avere l’occupazione Unicode. Otteniamo 12.290 bytes.

La dimensione di default del pacchetto TDS e’ 4096 (4KB). Con questa impostazione saranno necessari almeno 4 pacchetti (16.384 bytes) per inviare il SQL Batch message da SSMS a SQL Server. Supponiamo di voler minizzare il numero di pacchetti inviati per cui decidiamo di negoziare un packet size di 32.767 bytes (massimo consentito). Per farlo serve modificare l’impostazione del server SQL? La risposta e’ no per cui lasciamo il server al valore di default:

Ma assicuriamoci di modificare lato SSMS il parametro corretto:

Test

Ora attiviamo NetMon ed eseguiamo la query da SSMS. Il risultato (colorato e filtrato) e’ il seguente:

Ho evidenziato i pacchetti da SSMS a SQL. Si nota subito una cosa interessante: benche’ abbiamo impostato il packet size a 32.767 il layer sottostante (TCP) ha comunque deciso di segmentare il messaggio in piu’ pacchetti separati (nel mio caso di 1448 bytes). Cio’ e’ atteso e documentato qui http://msdn.microsoft.com/en-us/library/aa174503(v=SQL.80).aspx:

You can configure the SQL Server packet size, which is the size of the TDS packets. The size of the TDS packets defaults to 4 KB on most clients (DB-Library applications default to 512 bytes), which testing has shown to be the optimal TDS packet size in almost all scenarios. The size of the TDS packets can be larger than the size of the packets in the underlying protocol. If this is the case, the protocol stack on the sending computer disassembles the TDS packets automatically into units that fit into the protocol packets, and the protocol stack on the client computer reassembles the TDS packets on the receiving computer.

Cio’ vuol dire che per calcolare la dimensione totale del nostro messaggio TDS dobbiamo sommare tutti i pacchetti TCP componenti il messaggio TDS. Nell’esempio abbiamo 8 pacchetti TCP da 1448 bytes e 1 pacchetto (l’ultimo) da 736 bytes. In totale, quindi, il messaggio TDS ha dimensione 12.320 bytes.

Ora ripetiamo l’esperimento rinegoziando il network packet TDS a 8.192 bytes. In questo caso saranno necessari 2 pacchetti TDS per inviare il batch di cui sopra:

Sommando i pacchetti (8 da 1448 bytes e 1 da 744 bytes) si ottiene 12.328 bytes.

Risultato

Nel primo caso abbiamo utilizzato un TDS network packet size di 32.767 bytes e abbiamo effettuato un traffico TCP di 12.320 bytes. Nel secondo caso abbiamo abbassato il network packet size a 8.192 bytes e abbiamo effettuato un traffic TCP di 12.328 bytes. La differenza e’ di 8 bytes.

A cosa sono dovuti? E’ l’header in piu’ dovuto al fatto che abbiamo inviato 2 pacchetti TDS invece che 1. Vi rimando qui per maggiori dettagli http://msdn.microsoft.com/en-us/library/dd340948(v=PROT.13).aspx .

Confrontando con l’occupazione del semplice statement Unicode (12.290 bytes) avanzano 30 bytes. Esclusi gli 8 precedentemente evidenziati ne rimangono ancora 22. Questo valore e’ quello che ci attendiamo per il campo All_Header (cfr http://msdn.microsoft.com/en-us/library/dd304416(v=PROT.13).aspx ). L’esempio cita infatti:

<TotalLength>

          <DWORD>16 00 00 00 </DWORD>

</TotalLength>

0x16 in esadecimale equivale esattamente a 22 in decimale.

Aggiungo come riferimento la progressione dell’overhead (dell’header TDS) in percentuale per uno statement di 65.536 bytes in funzione del network packet size. Come si nota anche con un packet size di 512 bytes l’overhead e’ inferiore al 2%.

 

Happy coding

Francesco Cogno