What columnar means
A traditional row-oriented DataFrame stores tuples in memory: row 1's (col1, col2, col3), then row 2's (col1, col2, col3), etc. Reading column 1 alone means touching every row's memory; the CPU pulls in col2 and col3 data it never uses.
Columnar storage inverts the layout. Each column is its own contiguous buffer — all of col1's values laid out in memory, then all of col2's, then all of col3's. Reading column 1 touches exactly column 1's memory.
The trade: row inserts touch N buffers (one per column); column scans touch one. Analytics workloads are dominated by column scans, so columnar wins by ~10× on memory bandwidth for a 10-column table (one column scan touches 1/10 of a row-store's cache lines). OLTP workloads are dominated by single-row inserts, so row stores still win there.