Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

This has been bugging me for a while. Most of the time, when it comes to storing data in structures such as hashtables, programmers, books and articles insist that indexing elements in said structures by String values is considered to be bad practice. Yet, so far, I have not found a single such source to also explain WHY it is considered to be bad practice. Does it depend on the programming language? On the underlying framework? On the implementation?

Take two simple examples, if it helps:

An SQL-like table where rows are indexed by a String primary key.

A .NET Dictionary where the keys are Strings.

share|improve this question
5  
Having string keys is not a bad idea in general. I suspect those statements were made in a context where a better key type is available. I have have .net dictionaries with string keys all the time. Can you give some examples of this claim? –  CodesInChaos Mar 2 '13 at 21:49
3  
You usually want primary keys that don't change over the lifetime of an object/row. So for example username as the primary key of a users table is probably not the best idea, and you'd prefer an auto-increment id. But that username is a string is only incidental, being a mutable property is the main issue –  CodesInChaos Mar 2 '13 at 21:55
    
In a database, consider how would would index strings as opposed to integers. –  MichaelT Mar 2 '13 at 21:58
    
@CodesInChaos I wish I could remember where I found most of the cases, but for now I can paste the bit which reminded me of the issue. It was from a GDC slideshow by Valve which discussed game dialogues and storing facts about the world in <key=string, value=object> pairs. –  Alex M. Mar 2 '13 at 21:59
1  
Strings are fine. Just not 'magic' strings. So, when using a hash table, make sure you don not have naked strings in your code. You should avoid large text values as keys because they don't perform well, but in most real world situations a short text string is just as fast as an integer (they are not massive databases). You can also use alternate keys, for example, the primary key is a number but there's also a 'slug' or unique string that's also unique. –  ipaul Mar 3 '13 at 16:38
show 3 more comments

5 Answers

up vote 8 down vote accepted

It all has to do with the two things basically:

1) The speed of lookup (where integers for instance fare much better)

2) The size of indexes (where string indexes would explode)

Now it all depends on your needs and the size of the dataset. If a table or a collection has like 10-20 elements in it, the type of the key is irrelevant. It will be very fast even with a string key.

P.S. May not be related to your question, but Guids are considered bad for database keys too (16 byte Guid vs. 4 byte integer). On large data volumes Guids do slow down lookup.

share|improve this answer
    
Not always - incremental GUIDs are possible. Indexes will still be bigger, but the lookup penalty won't be nearly as bad. –  Sam Mar 2 '13 at 23:55
    
Actually they're fine. You have to look at the relationship between the time disk IO time and comparing values in memory. Since disk access times overwhelm memory comparison, the only thing that really matters in analyzing database performance is IO. Whether the key is a GUID, string or an integer is not really critical. The index size affects how many index values fit in one page, but whether the key is a 4 byte int (which may not be large enough and can't be client generated) or a 16 byte value is not a significant concern. In some databases the rowId's can be 16 bytes in size. –  ipaul Mar 3 '13 at 16:34
add comment

There is one more issue with using strings as keys, or more accurately, using string literals as keys, setting aside pure performance/efficiency reasons. Typos. If you use string literals as keys in a dictionary, you're setting yourself up for a nasty surprise when one "ReceiverId" becomes a "RecieverId". Set up constants to store the key values and reuse them whenever you access the dictionary.

Trivial and obvious, you can say, yet a stunning number of .NET code examples around the web uses string literals, propagating this dubious practice. ASP.NET with all the Sessions, ViewStates and QueryParams strewn across the codebase is particularly guilty here.

share|improve this answer
    
Not trivial IMHO. I've also seen cases where there are keys "1" and "1 " in the same table. –  p.s.w.g Mar 3 '13 at 0:00
    
Get's even more amusing when you throw case sensitivity in the mix as well. Seen loads of people including myself stumble directly into that one. –  Tony Hopkinson Mar 3 '13 at 16:04
add comment

There are many tradeoffs here. Actually I use string keys frequently, but often I include surrogate secondary keys for joins (obviously it would be the other way around if I was using MySQL). There are cases where I don't however.

First I am a fan of declaring natural keys as the primary key where the db can handle this well (PostgreSQL for example). This helps with normalization and makes for clearer database design. Surrogate keys make joining easier.

There are two reasons I usually add surrogate keys:

  1. It isn't always clear what a natural key is. Sometimes these have to be changed. Changing a natural, composite key when it is used for joins and referential integrity is complicated and error prone.

  2. Join performance on composite keys is problematic and once you go down the natural key route, you get stuck there.

In cases where a natural key is definitional, single column, and text, however, I usually join on the string key. My reason for doing so is that this often avoids joins on lookup. The most common use is providing proper db design around the use case of enum types. In most cases, these do not require the extra join for routine queries. So where this is the case, string keys as join keys makes perfect sense.

For example in LedgerSMB, we store account categorizations. These are identifed by string reference.and some other data is stored with the string reference which is used to enforce rules regarding the combinations of categorizations that can affect an account. The only time that logic is needed is when saving a set of categorizations, so we join on the string key.

As to why the default would be integer keys, I don't think it's just a question of index size. A big issue is management of keys. Since the key is arbitrary and you may be dealing with millions of records, you have to have a way of generating unique strings. There are cases where people use UUIDs for this, but there is a non-zero chance of UUID collision, and where billions of records are stored, this chance becomes high enough one might actually see while the chance of collision with incremented integer types is zero by definition.

share|improve this answer
    
It's not non-zero if you manage to make the integer type wrap around back to zero. For an unsigned 32-bit type, that is only 4G away, which is disturbingly close with “billions of records”… –  Donal Fellows Mar 3 '13 at 7:46
    
If you have a db that you can tell "error rather than wrap around" it is zero. At any rate it is easier to manage the possibility of collision with incrementing integers than with pseudorandom values. –  Chris Travers Mar 3 '13 at 9:00
add comment

There are a number of potential issues with using strings as keys, especially when it comes to sql-like tables. As mentioned by @bunny, the indexes for your tables are going to be bigger, but I think more significantly, any foreign key relationships to the table will involve BOTH tables to have contain the string as opposed to a lighter-weight (integer) identifier. If you find that there are even more tables with references to the first, the string keys will be proliferated throughout your database.

share|improve this answer
add comment

It' not a bad idea in and of itself, it's usually with 20/20 hindsight a poor design compromise. The flexibility and range of string versus the additional cost and complexity.

If integer does the job range wise and the bulk of the expensive processing doesn't need to know what the integer represents, use one.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.