2011-04-08 84 views
7

我一直在研究和阅读有关SQL数据类型几天(我知道......我知道,这不是很长),我很难掌握的一件事是如何选择最好的数据键入可扩展性,效率和访问简易性。为MySQL选择数据类型?

我认为如何选择基本的数据类型(即int vs varchar)非常简单,但是如何选择blob和文本类型之类的东西。

MySQL的手册页很棒,但它们并不是我们电脑爱好者所钟爱的......高效。

我认为如果我们可以编译MySQL数据类型列表,每种类型的一般优点/缺点以及何时选择该数据类型都有意义,那将是非常棒的。

+1

http://www.google.com/search?q=performance+of+mysql+data+types(任何事情在第一页) – Ben 2011-04-08 00:42:29

+0

我喜欢这个问题,希望有一个深思熟虑的答案,这可以真正帮助我的服务器上的速度(如果我选择了错误的类型)。同时,这篇文章与此有关(和选择错误的数据类型有关的问题)http://m.pinboard.in/blog/173/ – Ben 2011-04-08 01:05:41

+0

@当然是一个链接到谷歌,你不认为阅读我的问题,我花了一些时间搜索和阅读什么是最好的。问题在于没有以有效的方式汇编这些信息,并且很好地描述了何时使用它们。如果你阅读5或6篇文章,你会得到大量的信息,但我们可以很容易地在wiki风格列表中匹配。它可以编辑和使用比筛选谷歌结果更​​好。搜索最好的文章是桃花,但它仍然不完整。 :/我想这里的答案可能会好得多。 – austinbv 2011-04-10 00:35:56

回答

11

MySQL字符串类型有两种变体:一种不带字符集标签,另一种带有字符集标签。

一个固定长度的字符串,在末尾用空格填充,是CHAR(n)。没有字符集标签的匹配类型是BINARY(n)。在CHAR(255) CHARSET utf8中存储字符串“hello”需要765个字节(字符串填充的空格为全长,存储为utf8,最坏情况空间使用3个字节/字符分配3 * 255个字节)。

带有一个或两个长度字节且没有填充的可变长度字符串是VARCHAR((n)。没有字符集标签的匹配类型是VARBINARY(n)。将字符串“hello”存储在VARCHAR(255) CHARSET utf8中6个字节(1个长度字节加上用于实际的文本5个字节)。存放字符串ク在同类型将采取(每个字符使用三个字节来表示它们1个长度字节加上3个字符)10个字节リス。

mysql> select hex('クリス'), length(hex('クリス'))/2 as bytes; 
+--------------------+--------+ 
| hex('クリス')  | bytes | 
+--------------------+--------+ 
| E382AFE383AAE382B9 | 9.0000 | 
+--------------------+--------+ 
1 row in set (0.02 sec) 

长度为1,2,3或4个字符的可变长度字符串是TINYTEXT,TEXT,MEDIUMTEXT和LARGETEXT。没有字符集标签的匹配类型是TINYBLOB,BLOB,MEDIUMBLOB和LARGEBLOB。

TEXT/BLOB-like类型与VARCHAR/VARBINARY-like类型在存储数据的方式和位置上有所不同,请参阅http://www.mysqlperformanceblog.com/2010/02/09/blob-storage-in-innodb/以获取有关TEXT/BLOB-like类型如何存储在InnoDB中的详细信息,具体取决于版本和ROW_FORMAT设置。出于性能方面的原因,您需要最新版本的InnoDB和“Barracuda”格式表。

除非您在服务器端构建复杂且内存紧张的解决方法,否则MySQL无法处理大于max_allowed_pa​​cket(默认值:1M)大小的任何数据。这进一步限制了TEXT/BLOB-like类型可以做什么,并且通常使LARGETEXT/LARGEBLOB类型在默认配置中无用。

对于没有字符集标签(BINARY,VARBINARY和%BLOB%)的类型,MySQL将接受收到的数据并将其写入磁盘。对于具有字符集标签的类型,MySQL会查看您宣布的客户端字符集为SET NAMES以及列定义的字符集标签。然后它将从连接字符集转换为列字符集并写入转换后的数据。您可以使用HEX()函数来检查它,例如SELECT HEX(str) FROM t WHERE id = ...

检索时,该连接宣布字符集与SET NAMES可以从它已经在写入时不同。 MySQL将再次检查列字符集标签与为此连接宣布的字符集,并在必要时将转换为连接字符集。

该转换相比,采取I/O招致这样的数据反正performancewise它并不重要选择哪种类型的磁盘时两种方式都可以忽略不计的性能损失。规则是:如果使用文本数据,则选择带有字符集标签的类型;如果不使用,则选择不带类型的类型。


经常问到一个相关的问题:我应该选择CHAR还是VARCHAR(分别是BINARY还是VARBINARY)?

对于InnoDB,答案总是:之所以选择可变长度的数据类型。 InnoDB中的固定长度数据类型没有性能优势,但如果您选择固定长度的数据类型,然后没有使用全部空间,则会有巨大的损失。另外,固定长度的SQL字符串类型有很多奇怪的规则,关于填充和修剪,最后使用空格,您可能无法学习。对于MySQL而言,情况可能不同,但几乎从不是。


另一个相关的问题:要不要我(分别为VARBINARY或BLOB)选择VARCHAR或TEXT我的琴弦?

的答案是使用最新的InnoDB,梭子鱼格式表格的版本,然后TEXT/BLOB。详细解释原因在于http://www.mysqlperformanceblog.com/2011/04/07/innodb-row-size-limitation/。那其结果是:无论使用哪种VARCHAR或预酷鱼格式TEXT/BLOB运行溢满了InnoDB的行大小限制,如果你有太多的单个行的风险。


最后:我应该在数据库中存储文件/图像/其他大型blob或文本数据?

该答案是:通常不会。与从文件系统提供文件相比,从数据库提供文件(http://mysqldump.azundris.com/archives/36-Serving-Images-From-A-Database.html)是一项昂贵的操作。如果可能的话,你会想这样做。有一种方法,http://www.blobstreaming.org/,但这是先进的技术,要求您完全控制您的执行环境,这在托管环境中从未如此。


要舍弃它:在MEMORY引擎表中没有可变长度的数据类型。所以,如果你看到“使用临时”在EXPLAIN输出,这意味着

  • VARCHAR转换为CHAR在临时表
  • VARBINARY转换成二进制

如果临时表通过这个过程变得比tmp_table_size或者max_heap_table_size大,它正在被转换成MyISAM格式并且到磁盘。

示例:您正在定义一个Ruby Active Record类User,其中包含标记为:string的十个字段。在表中,每个结果都是VARCHAR(255) CHARSET utf8

在您的代码库中的其他地方,正在使用Users的方式涉及计划using temporary。您正在负载下的磁盘操作中立即死亡,因为Users表的每一行现在在MEMORY中至少使用了7650个字节,其中大多数是用作填充的空格。这强制将临时表转换为MyISAM并写入磁盘。

  • 任何%TEXT%或%BLOB%类型不能在内存中表示,因此临时表进行到磁盘,即使它本来足够小,以根据上述的限制被保持在存储器中的MyISAM。

这意味着任何带有TEXT或BLOB类型的查询以及带有“使用临时”的计划都需要重写,以避免临时表碰到磁盘。

1

关于BLOB和TEXT(因为这是你的文章中唯一的具体问题):BLOB用于二进制数据,而TEXT用于文本数据。

使用适合您需求的最具体类型的列通常非常简单,并且如果它们中没有一个适合您的使用,则回退到泛型类型。

1

对于MySQL,有一个称为分析的过程,它将评估启发式数据的思想,即通知数据类型的最佳选择,并为枚举提供一个或多个值。

快速动态CONCAT脚本生成的SQL运行

select CONCAT(' SELECT ', COLUMN_NAME, ' FROM ', TABLE_NAME, ' procedure analyse() ;') 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE table_schema ="yourDbName" 
AND DATA_TYPE ="varchar" 
AND CHARACTER_MAXIMUM_LENGTH > 190 
AND COLUMN_KEY not in (' ') ; 

** SQL以上不评估的PK - 假设他们不是文本字段

的程序是有益的面色改变时基于数据使用的数据类型或通过移动或存储较小的数据包来获得更高的效率。

Percona博客有一个很好的适用于Drupal的程序分析工作示例。 https://www.percona.com/blog/2009/03/23/procedure-analyse/

一些研究是针对压缩它关系到更长utf8mb4指标 http://techblog.constantcontact.com/devops/space-the-final-frontier-a-story-of-mysql-compression/