Using one texture per tile is not very efficient. Especially since it means you cannot do batching (in any real sense).
If you NEED to have them as separate textures in your content-project for some reason (easier to edit one tile, etc), you can quite easily compile them into tilemaps after loading.
How you do this is basicly:
1: Load a number of tiles (lets say 40 32*32 tiles for now)
2: Figure out a nice texture-size for the tilemap:
square root of 40 is 6.something, so we round up to 7. 7*32 is 224, which is nice, but 256 is nicer, so lets make the texture 256x256. (you can make code that figures out this on the fly)
3: Create a Rendertarget2D which is the desired size.
4: Activate rendertarget.
5: Render tiles on rendertarget:
int x, y = 0;
foreach (var tile in allTiles)
{
RenderTile(tile, x*32, y*32);
x++;
if (x >= 8)
{
x = 0;
y++;
}
}
To betch-render you have a vertex-buffer with 4 * 40 vertices. each set of 4 has a value indicating index of the quad it belongs to (0,1,2,etc...). In your shader you have an array of matrixes[40] for position of the tiles, as well as an array of tileIndex (int[40]) for knowing which tile to render from the tilemap.
I'm sorry, but I don't have time to write all the shader-code right now :s
An other trick I have used in our games is pre-rendering the level onto large tiles (640x360), which reduces the number of draw-calls by a great deal, especially when dealing with 5+ layers of tiles from different tilesets. Only thing is that it does not work with dynamic tiles (animated tiles, etc), but you can mark those and render them normally if you want...