Your network traffic to the SQL database server includes MUCH more than just the data you're looking to transmit (as you have observed by seeing much more traffic received than just row data)
Before I start, let me disclaim a few things: I am in no way an expert on network traffic and protocols, but have spent a fair amount of time playing around with them to understand enough. I also do not know much about what protocol the particular DAC software, query combination, etc. would employ to bring you your requested data back. That being said, I cannot give an exact example. but the concepts should still apply.
Communication with SQL server occurs through various protocols, however we will focus on just 1 for the sake of argument: TDS (Tabular Data Stream) protocol. (You can read more about SQL Server Protocols at: You can read more on SQL Server Protocols at: http://msdn.microsoft.com/en-us/library/ff420673(v=sql.105).aspx). TDS uses the TCP protocol, thus a TDS packet is nothing more than a specification wrapped in a TCP packet).
With TCP, communications are basically with a Request / Response type of exchange involving many request / response / acknowledge packets. Again, I am by no means an expert on this, but you can read more at http://en.wikipedia.org/wiki/Transmission_Control_Protocol
The "acknowledge" (or confirmation) aspect of the communication alone accounts for a fair amount of overhead beyond just the row sizes you referenced. You can see an example of this in the image below where communication is occurring between a client application and a SQL server:
Additionally, within the actual packet being sent pack to the application from the DB server, there is a lot of overhead within the TCP packet protocol itself along with overhead within the TDS packet.
Lets focus just on the TDS packet's overhead that adds to your overall data transfer payload. Below are all documented (http://msdn.microsoft.com/en-us/library/dd340794.aspx) of what can be found in a TDS packet:
- ALTMETADATA
- ALTROW
- COLINFO
- COLMETADATA
- DONE
- DONEINPROC
- DONEPROC
- ENVCHANGE
- ERROR
- FEATUREEXTACK
- INFO
- LOGINACK
- NBCROW
- OFFSET
- ORDER
- RETURNSTATUS
- RETURNVALUE
- ROW <- This is where your data is
- SESSIONSTATE
- SSPI
- TABNAME
- TVP ROW
And all the while, really your ACTUAL data (in the case you described above) is located within the ROW portion of the packet.
Below is a screenshot showing an ASCII version of 1 TDS packet. The highlighted portion of the packet frame (on the right) is the actual row data. All the rest is just overhead that makes the entire communication and ancillary things just work.
And this does not even include the overhead (albeit necessary) created by TCP itself.
In summary
You're transferring an extremely large amount of data and that data will always have overhead.
- If the data is going to be summarized in the end, then summarize it on the DB server before shipping it.
- If the data is going to be searched, offload that search to the DB server and just return what you need
- If you need to list the data out (each row), then you're probably showing only a sub-set of results per page - only return those results you need through something like a
SELECT TOP 50 .... WHERE ....
There are many other solutions depending upon your actual use of the data, but these are just some ideas.
Hope this helps!