Your premise is somewhat correct. The benefits of an index of the performance of performing a lookup (SELECT
). If you have a list of 1,000 last names (regardless of the number of unique names), and you want to find those that equal "Smith", you would have to look through all 1,000 rows to find which entries (if any) match your query. This can be very slow, as it your performance gets worse based on how many rows you have (regardless of the number of unique rows).
Now imagine you have your names alphabetized by Last Name. If you want to find any entries with the last name of "Smith", you could do a "binary search": pick the middle entry and see if the last name is less than or greater than "Smith" in alphabetical order. If it's less, then throw away the first half of the names and only deal with the last half. Pick the middle entry of the remaining names and compare it to Smith, etc...
What you've done is reduced your search time. Now, rather than having to check all n entries to find "Smith", you only have to check log(2)n entries, which can be much smaller for large values of n.
This is essentially what an index does, except the often use B+ trees (similar to the binary tree approach mentioned above but with some extra nice properties) that will help.
Regarding your uniqueness question, yes, you can apply an index to a non-unique column. An index is often used on a column which must be unique (such as a primary key) because, without an index, it can be very expensive to maintain uniqueness in a column. For instance, imagine that you want to add an entry with the last name of "Smith" but you have a unique constraint on the Last Name column. How do you know if there's already an entry named "Smith"? You'll have to search for it. Without an index, that will require examining n entries; with an index, only log(2)n. So it's usually a good idea to keep an index on a unique column to keep the performance reasonable.
Also, the Wikipedia article on database indexes answers your question in more detail.