Mar*_*wer 51 mysql index full-text-search varchar
我在MySql 数据库中工作,有一个这样的表:
+--------------+
| table_name |
+--------------+
| myField |
+--------------+
Run Code Online (Sandbox Code Playgroud)
...我需要进行很多这样的查询(列表中有 5-10 个字符串):
SELECT myField FROM table_name
WHERE myField IN ('something', 'other stuff', 'some other a bit longer'...)
Run Code Online (Sandbox Code Playgroud)
将有大约 24.000.000 个唯一行
1)我应该使用FULLTEXTor 和INDEXkeyVARCHAR(150)吗?
2)如果我将字符从 150 增加到 220 或 250 ......会产生很大的不同吗?(有没有办法计算它?)
3)正如我所说,它们将是唯一的,所以myField应该是一个PRIMARY KEY。向已经是 VARCHAR INDEX/FULLTEXT 的字段添加 PRIMARY KEY 是不是很少见?
Rol*_*DBA 81
CREATE TABLE mytable
(
id int not null auto_increment,
myfield varchar(255) not null,
primary key (id),
key (myfield)
);
Run Code Online (Sandbox Code Playgroud)
如果您这样索引,您可以查找整个字符串或执行向左的 LIKE 搜索
CREATE TABLE mytable
(
id int not null auto_increment,
myfield varchar(255) not null,
primary key (id),
fulltext (myfield)
);
Run Code Online (Sandbox Code Playgroud)
您可以有效地搜索单个关键字以及整个短语。您将需要定义一个自定义停用词列表,因为MySQL 不会索引 543 个词。
这是我过去两年关于 FULLTEXT 索引的其他帖子
May 23, 2011:优化 mysql 全文搜索 (StackOverflow)Oct 25, 2011: FULLTEXT 索引在 BOOLEAN MODE 中被忽略,“字数”有条件Jan 26, 2012: mysql全文搜索my.cnf优化May 07, 2012:MySQL EXPLAIN 不显示 FULLTEXT 的“使用索引”CREATE TABLE mytable
(
id int not null auto_increment,
myfield varchar(255) not null,
hashmyfield char(32) not null,
primary key (id),
key (hashmyfield)
);
Run Code Online (Sandbox Code Playgroud)
如果您正在寻找一个特定值并且这些值的长度可能远远超过 32 个字符,您可以存储散列值:
INSERT INTO mytable (myfield,hashmyfield)
VALUES ('whatever',MD5('whatever'));
Run Code Online (Sandbox Code Playgroud)
这样,您只需搜索哈希值即可检索结果
SELECT * FROM mytable WHERE hashmyfield = MD5('whatever');
Run Code Online (Sandbox Code Playgroud)
试一试 !!!
Mr.*_*r.M 20
MySQL 使您能够定义前缀索引,这意味着您可以从要索引的原始字符串中定义前 N 个字符,诀窍是选择一个足够长的数字 N 以提供良好的选择性,但又足够短以节省空间。前缀应该足够长,以使索引几乎与索引整个列时一样有用。
在我们进一步讨论之前,让我们定义一些重要的术语。索引选择性是总不同索引值与总行数的比率。这是测试表的一个示例:
+-----+-----------+
| id | value |
+-----+-----------+
| 1 | abc |
| 2 | abd |
| 3 | adg |
+-----+-----------+
Run Code Online (Sandbox Code Playgroud)
如果我们只索引第一个字符(N=1),那么索引表将如下表所示:
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| a | 1,2,3 |
+---------------+-----------+
Run Code Online (Sandbox Code Playgroud)
在这种情况下,索引选择性等于 IS=1/3 = 0.33。
现在让我们看看如果我们将索引字符的数量增加到两个(N=2)会发生什么。
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| ab | 1,2 |
| ad | 3 |
+---------------+-----------+
Run Code Online (Sandbox Code Playgroud)
在这种情况下,IS=2/3=0.66 这意味着我们增加了索引选择性,但我们也增加了索引的大小。关键是要找到的最小数N,这将导致以最大的索引选择性。
有两种方法可以对数据库表进行计算。我将对此数据库转储进行演示。
假设我们要将表雇员中的列last_name添加到索引中,并且我们希望定义将产生最佳索引选择性的最小数字N。
首先让我们找出最常见的姓氏:
select count(*) as cnt, last_name from employees group by employees.last_name order by cnt
+-----+-------------+
| cnt | last_name |
+-----+-------------+
| 226 | Baba |
| 223 | Coorg |
| 223 | Gelosh |
| 222 | Farris |
| 222 | Sudbeck |
| 221 | Adachi |
| 220 | Osgood |
| 218 | Neiman |
| 218 | Mandell |
| 218 | Masada |
| 217 | Boudaillier |
| 217 | Wendorf |
| 216 | Pettis |
| 216 | Solares |
| 216 | Mahnke |
+-----+-------------+
15 rows in set (0.64 sec)
Run Code Online (Sandbox Code Playgroud)
如您所见,姓氏Baba是最常见的名字。现在我们要找到最常出现的last_name前缀,从五个字母的前缀开始。
+-----+--------+
| cnt | prefix |
+-----+--------+
| 794 | Schaa |
| 758 | Mande |
| 711 | Schwa |
| 562 | Angel |
| 561 | Gecse |
| 555 | Delgr |
| 550 | Berna |
| 547 | Peter |
| 543 | Cappe |
| 539 | Stran |
| 534 | Canna |
| 485 | Georg |
| 417 | Neima |
| 398 | Petti |
| 398 | Duclo |
+-----+--------+
15 rows in set (0.55 sec)
Run Code Online (Sandbox Code Playgroud)
每个前缀的出现次数要多得多,这意味着我们必须增加 N 数,直到值几乎与前一个示例中的值相同。
这是 N=9 的结果
select count(*) as cnt, left(last_name,9) as prefix from employees group by prefix order by cnt desc limit 0,15;
+-----+-----------+
| cnt | prefix |
+-----+-----------+
| 336 | Schwartzb |
| 226 | Baba |
| 223 | Coorg |
| 223 | Gelosh |
| 222 | Sudbeck |
| 222 | Farris |
| 221 | Adachi |
| 220 | Osgood |
| 218 | Mandell |
| 218 | Neiman |
| 218 | Masada |
| 217 | Wendorf |
| 217 | Boudailli |
| 216 | Cummings |
| 216 | Pettis |
+-----+-----------+
Run Code Online (Sandbox Code Playgroud)
这是 N=10 的结果。
+-----+------------+
| cnt | prefix |
+-----+------------+
| 226 | Baba |
| 223 | Coorg |
| 223 | Gelosh |
| 222 | Sudbeck |
| 222 | Farris |
| 221 | Adachi |
| 220 | Osgood |
| 218 | Mandell |
| 218 | Neiman |
| 218 | Masada |
| 217 | Wendorf |
| 217 | Boudaillie |
| 216 | Cummings |
| 216 | Pettis |
| 216 | Solares |
+-----+------------+
15 rows in set (0.56 sec)
Run Code Online (Sandbox Code Playgroud)
这是非常好的结果。这意味着我们可以在列last_name上创建索引,只索引前 10 个字符。在表定义中,last_name列被定义为VARCHAR(16),这意味着我们为每个条目节省了 6 个字节(如果姓氏中有 UTF8 字符则更多)。在这个表中有 1637 个不同的值乘以 6 个字节大约是 9KB,想象一下如果我们的表包含数百万行,这个数字会如何增长。
您可以在我的帖子Prefixed index in MySQL 中阅读其他计算N数的方法。
使用 MD5 和 SHA1 函数来生成应该被索引的值也不是一个好方法。为什么?在文章中阅读如何为 MySQL 数据库中的主键选择正确的数据类型
| 归档时间: |
|
| 查看次数: |
74544 次 |
| 最近记录: |