2011-09-17 46 views
-2

我有一个数据库中的表像这样 关键词有效的搜索查询

  • ID INT(11)
  • U_ID INT(11)
  • 关键字文本
  • CREATE_DATE INT的结构( 11)

U_ID为外键,id是主键

关键字字段是用户创建的用逗号分隔的单词列表 我想知道是否有人可以建议有效的查询来搜索这样的表。

+2

切勿在数据库中使用CSV。这是一个主要的罪恶! – Johan

回答

0

如果使用MyISAM,则可以在字段keywords上创建全文索引。然后搜索使用:

select * from keywords k where match('test') against(k.keywords); 

当然,在数据库中的CSV只是你可以做的最糟糕的事情。你应该把关键字放在一个单独的表格中。确保对所有表使用InnoDB。

Table tags 
------------- 
id integer auto_increment primary key 
keyword_id integer foreign key references keywords(id) 
keyword varchar(40) 

现在您可以选择使用:

SELECT k.* FROM keywords k 
INNER JOIN tags t ON (t.keyword_id = k.id) 
WHERE t.keyword LIKE 'test' //case insensitive comparison. 

比CSV很多快得多。

+0

谢谢,我认为这将简化事情 – MrFoh

2

您应该更改数据库设计,以便拥有一个名为user_keyword的表并将每个关键字存储在单独的行中。然后,您可以索引此表并轻松地和有效地搜索它:

WHERE keyword = 'foo' 

如果不能修改数据库那么你可以使用FIND_IN_SET但它不会是非常有效:

WHERE FIND_IN_SET('foo', keywords) 
+0

如何更改数据库设计 – MrFoh

+0

修改数据库将意味着我将不得不使用前面的结构编写代码 – MrFoh

+0

WHERE FIND_IN_SET('foo',keywords)'就够了,'!= 0'部分不是需要。 – Johan

-1

你有2种选择:

  1. 重新structor数据库,创建一个名为关键词额外的表,并应包括U_ID这将是映射到您的用户表的外键,这样你可以很容易地插入每个关键字输入到关键词表,然后搜索它使用的东西:

SELECT * FROM Keywords WHERE keyword LIKE %KEYWORD%

  1. 你可以得到关键字字段中,单独的关键字,并使用您的首选语言把它们放到一个数组,然后搜索数组。
+2

错误的答案,在一个带有“book,testing”的CSV列中,即使'test'本身不在该列中,这也会给出匹配。在SQL和php中混合查询本身就是一种反模式。 – Johan

1

单独的keywords在它自己的表中,通过FOREIGN KEY将它连接到旧表,将它索引,并且您将能够有效地搜索关键字前缀的确切关键字。

例如:

id U_id keywords create_date 
1 - A,B,C - 

变为:

PARENT_TABLE: 
id U_id create_date 
1 - - 

CHILD_TABLE: 
id keyword 
1 A 
1 B 
1 C 

提供有上keyword索引,以下查询应该是有效的:

SELECT * FROM PARENT_TABLE 
WHERE id IN (SELECT id FROM CHILD_TABLE WHERE keyword = ...) 

--- EDIT ---

根据Johan的下面的评论,似乎InnoDB在大多数其他数据库下使用Oracle或“集群”下的“索引组织表”。假设您不需要查询“从父母到孩子”(即,“给我定的ID的所有关键字”),对CHILD_TABLE的PRIMARY KEY应该是:

{keyword, id} 

由于keyword是复合索引中的第一个字段,WHERE keyword = ...(或WHERE keyword LIKE 'prefix%')可以直接使用该索引。

+0

没有自己的PK的innoDB表将表现得很差。 – Johan

+0

@Johan OK,我忘了提及这一点,但CHILD_TABLE的主键是:{id,keyword}。 –

+0

@Johan顺便说一句,为什么它表现不佳(我不是MySQL/innoDB专家)? –