Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a maintainable way to store large text fields without sacrificing performance?

I have been dancing around this issue for awhile but it keeps coming up. We have a system and our may of our tables start with a description that is originally stored as an NVARCHAR(150) and I then we get a ticket asking to expand the field size to 250, then 1000 etc, etc...

This cycle is repeated on ever "note" field and/or "description" field we add to most tables. Of course the concern for me is performance and breaking the 8k limit of the page. However, my other concern is making the system less maintainable by breaking these fields out of EVERY table in the system into a lazy loaded reference.

So here I am faced with these same to 2 options that have been staring me in the face. (others are welcome) please lend me your opinions.

  1. Change all may notes and/or descriptions to NVARCHAR(MAX) and make sure we do exclude these fields in all listings. Basically never do a: SELECT * FROM [TableName] unless is it only retrieving one record.

  2. Remove all notes and/or description fields and replace them with a forign key reference to a [Notes] table.

    CREATE TABLE [dbo].[Notes] (
    [NoteId] [int] NOT NULL,
    [NoteText] [NVARCHAR]
    (MAX)NOT NULL )

Obviously I would prefer use option 1 because it will change so much in our system if we go with 2. However if option 2 is really the only good way to proceed, then at least I can say these changes are necessary and I have done the homework.


UPDATE: I ran several test on a sample database with 100,000 records in it. What I find is that the because of cluster index scans the IO required for option 1 is "roughly" twice that of option 2. If I select a large number of records (1000 or more) option 1 is twice as slow even if I do not include the large text field in the select. As I request less rows the lines blur more. I a web app where page sizes of 50 or so are the norm, so option 1 will work, but I will be converting all instances to option 2 in the (very) near future for scalability.

like image 221
Jamey McElveen Avatar asked Feb 17 '09 22:02

Jamey McElveen


People also ask

What is the maximum size of characters stored in a field declared with a text?

A TEXT column with a maximum length of 65,535 (216 − 1) characters. The effective maximum length is less if the value contains multibyte characters. Each TEXT value is stored using a 2-byte length prefix that indicates the number of bytes in the value. An optional length M can be given for this type.

What is long text data type?

A Long Text field can be useful for storing large amounts of information, such as notes, comments, and descriptions. The Long Text data type stores up to 65,536 alphanumeric characters and supports rich text formatting, such as different colors, fonts, and highlighting.

What type of data you should not store in a database?

Finally, you shouldn't store credit card information in your database unless you absolutely need to. This includes credit card owner names, numbers, CVV numbers, and expiration dates.


2 Answers

Option 2 is better for several reasons:

  1. When querying your tables, the large text fields fill up pages quickly, forcing the database to scan more pages to retrieve data. This is especially taxing when you don't actually need to return the text data.
  2. As you mentioned, it gives you a clean break to change the data type in one swoop. Microsoft has deprecated TEXT in SQL Server 2008, so you should stick with VARCHAR/VARBINARY.
  3. Separate filegroups. Having all your text data in a slower, cheaper storage location might be something you decide to pursue in the future. If not, no harm, no foul.

While Option 1 is easier for now, Option 2 will give you more flexibility in the long-term. My suggestion would be to implement a simple proof-of-concept with the "notes" information separated from the main table and perform some of your queries on both examples. Compare the execution plans, client statistics and logical I/O reads (SET STATISTICS IO ON) for some of your queries against these tables.

A quick note to those suggesting the use of a TEXT/NTEXT from MSDN:

This feature will be removed in a future version of Microsoft SQL Server. Avoid using this feature in new development work, and plan to modify applications that currently use this feature. Use varchar(max), nvarchar(max) and varbinary(max) data types instead. For more information, see Using Large-Value Data Types.

like image 138
Taylor Gerring Avatar answered Sep 28 '22 16:09

Taylor Gerring


I'd go with Option 2.

You can create a view that joins the two tables to make the transition easier on everyone, and then go through a clean-up process that removes the view and uses the single table wherever possible.

like image 36
Tom Ritter Avatar answered Sep 28 '22 15:09

Tom Ritter