Here's a better solution, using a Merkle tree.
Suppose the string $S$ is $n$ letters long. Build a binary tree with $n$ leaves, with each leaf corresponding to one letter in the string. Then, each node corresponds to a substring: the $i$th leaf corresponds to the $i$th letter in the string, and an internal node $x$ corresponds to the substring obtained by concatenating all of the leaves that are descendants of $x$. Now, you can store at each node of the tree the MAC of the substring it corresponds to. This is all done in a precomputation.
Once you've precomputed the binary tree, you can authenticate any substring $T$ of $S$ as follows: $T$ can be written as the concatenation of the strings at $O(\lg n)$ nodes in the tree. Therefore, to authenticate $T$, you send the MACs at those nodes. In this way, the authenticator is $O(\lg n)$ in length. This is better than your trivial solution, in terms of the length of the authenticator (as your trivial solution requires an authenticator that is $O(|T|)$ in length). In your storage setting, the length of the authenticator corresponds to the amount of data that must be read from storage to authenticate a particular substring $T$.
If your goal is solely to optimize the length of the authenticator, You might be able to build an even shorter authenticator using set accumulators, though the performance cost would likely be much higher. Given a string $S$, you construct a set of pairs $\langle i, S_i \rangle$, then use a set accumulator construction to sign that set; now it is possible to derive a signature on any subset, such as one corresponding to a substring of consecutive letters from $S$.
Another alternative might be to use hash chaining or MAC chaining. For MAC chaining, you could do the following: let $Y_i = MAC(Y_{i-1} || S_i)$, for each $i$. You can store all of the $Y_i$'s alongside the string. Then, to authenticate a substring $S_{i..j}$ of $S$, you read $Y_{i-1}$, do $j-i$ MAC operations to run forward along the substring, and check that the result matches $Y_j$. Of course, as an engineering optimization, it would be possible to store the $Y_i$ values for only every $k$th index $i$, for some $k$. I don't know whether this will be better in any sense than the other schemes.
You might also be interested in the following research papers:
Homomorphic signature schemes. Robert Johnson, David Molnar, Dawn Song, and David Wagner. RSA 2002, Cryptographer's Track. See particularly Section 4, redactable signatures.
Sanitizable Signatures. Giuseppe Ateniese, Daniel H. Chou, Breno de Medeiros, and Gene Tsudik. ESORICS 2005.
Given that you are focusing on stored data, you might also like to look at the line of research on memory integrity checkers, e.g.,
Checking the correctness of memories. Manuel Blum, William S. Evans, Peter Gemmell, Sampath Kannan, and Moni Naor. Algorithmica, 12(2/3):225–244, 1994.
The Complexity of Online Memory Checking. Moni Naor, Guy N. Rothblum. FOCS 2005.