The DataReader provides an unbuffered stream of data that allows procedural logic to efficiently process results from a data source sequentially. The DataReader is a good choice when retrieving large amounts of data because the data is not cached in memory. There's only row row of data in memory at any time, which thereby reduces the memory requirements. It is obvious that if the application requires sequential, read only data, then the DataReader object will be the best choice from a performance point of view.
We should keep in mind that while the DataReader is open, the connection is used exclusively by it. This may hamper the performance of your applications. To avoid this, the DataReader object should be closed explicitly by using its close method as soon as its job is done.