For the moment, I'm happy with this implementation's performance, but perhaps we could benchmark it under a few different sort scenarios.

Do you think we should attempt the stacking?

I'd also consider doing it as a postprocess, so that the current copy-once concatenation continues to work, and the need-to-sort and don't-need-to-sort cases don't get confused:
```python
for start, stop in izip(self.indptr[ui], self.indptr[ui + 1]):
    inds = self.indices[start:stop]
    order = np.argsort(inds)
    np.take(inds, order, out=inds)
    data = self.data[start:stop]
    np.take(data, order, out=data)
```
but this may, again, be slower than `sort_indices`