title: SQL Server Search Proper Names Full Text Index vs LIKE + SOUNDEX
body: <p>I have a database of names of people that has (currently) 35 million rows. I need to know what is the best method for quickly searching these names. The current system (not designed by me), simply has the first and last name columns indexed and uses "LIKE" queries with the additional option of using SOUNDEX (though I'm not sure this is actually used much). Performance has always been a problem with this system, and so currently the searches are limited to 200 results (which still takes too long to run). So, I have a few questions:</p>
  
  <ol>
  <li>Does full text index work well for proper names?</li>
  <li>If so, what is the best way to query proper names? (CONTAINS, FREETEXT, etc) </li>
  <li>Is there some other system (like Lucene.net) that would be better?</li>
  </ol>
  
  <p>Just for reference, I'm using Fluent NHibernate for data access, so methods that work will with that will be preferred. I'm using SQL Server 2008 currently.</p>
  
  <p><strong>EDIT</strong> I want to add that I'm very interested in solutions that will deal with things like commonly misspelled names, eg 'smythe', 'smith', as well as first names, eg 'tomas', 'thomas'.</p>
  
  <p><strong>Query Plan</strong></p>
  
  <pre><code>  |--Parallelism(Gather Streams)
         |--Nested Loops(Inner Join, OUTER REFERENCES:([testdb].[dbo].[Test].[Id], [Expr1004]) OPTIMIZED WITH UNORDERED PREFETCH)
              |--Hash Match(Inner Join, HASH:([testdb].[dbo].[Test].[Id])=([testdb].[dbo].[Test].[Id]))
              |    |--Bitmap(HASH:([testdb].[dbo].[Test].[Id]), DEFINE:([Bitmap1003]))
              |    |    |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([testdb].[dbo].[Test].[Id]))
              |    |         |--Index Seek(OBJECT:([testdb].[dbo].[Test].[IX_Test_LastName]), SEEK:([testdb].[dbo].[Test].[LastName] &gt;= 'WHITDþ' AND [testdb].[dbo].[Test].[LastName] &lt; 'WHITF'),  WHERE:([testdb].[dbo].[Test].[LastName] like 'WHITE%') ORDERED FORWARD)
              |    |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([testdb].[dbo].[Test].[Id]))
              |         |--Index Seek(OBJECT:([testdb].[dbo].[Test].[IX_Test_FirstName]), SEEK:([testdb].[dbo].[Test].[FirstName] &gt;= 'THOMARþ' AND [testdb].[dbo].[Test].[FirstName] &lt; 'THOMAT'),  WHERE:([testdb].[dbo].[Test].[FirstName] like 'THOMAS%' AND PROBE([Bitmap1003],[testdb].[dbo].[Test].[Id],N'[IN ROW]')) ORDERED FORWARD)
              |--Clustered Index Seek(OBJECT:([testdb].[dbo].[Test].[PK__TEST__3214EC073B95D2F1]), SEEK:([testdb].[dbo].[Test].[Id]=[testdb].[dbo].[Test].[Id]) LOOKUP ORDERED FORWARD)
  </code></pre>
  
  <p>SQL for above:</p>
  
  <pre><code>SELECT * FROM testdb.dbo.Test WHERE LastName LIKE 'WHITE%' AND FirstName LIKE 'THOMAS%'
  </code></pre>
  
  <p>Based on advice from Mitch, I created an index like this:</p>
  
  <pre><code>CREATE INDEX IX_Test_Name_DOB
  ON Test (LastName ASC, FirstName ASC, BirthDate ASC)
  INCLUDE (and here I list the other columns)
  </code></pre>
  
  <p>My searches are now incredibly fast for my typical search (last, first, and birth date).</p>