使用LIKE'%term%'的查询非常慢

时间:2014-01-28 09:20:17

标签: mysql innodb sql-like

我有一个InnoDB表,大约有1,000,000行:

Data            164.7   MiB
Index           250.1   MiB
Overhead        168.0   MiB
Effective       246.8   MiB
Total           414.8   MiB

表格结构:

CREATE TABLE IF NOT EXISTS `gift` (
  `tm` varchar(15) NOT NULL,
  `col` smallint(2) NOT NULL,
  `myindex` varchar(255) NOT NULL,
  `date` int(10) NOT NULL,
  KEY `tm` (`tm`),
  KEY `date` (`date`),
  KEY `myindex` (`myindex`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

tm是由PHP生成的非重复字符串(产品ID),

date存储使用strtotime('now')

myindex存储搜索关键字

因为某些产品的描述较长(超过255个字符),所以col是多个部分的长描述(相同的产品,关键字第1部分,关键字第2部分......)。

这样的查询将会产生(总计10次,查询耗时51.0829秒)

SELECT * 
FROM gift
WHERE myindex LIKE  '% keywords1 %'
AND myindex LIKE  '% keywords2 %'
GROUP BY tm
ORDER BY DATE DESC 
LIMIT 10

做出解释,得到:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE      gift    index   NULL            date    4   NULL 10 Using where; Using temporary

possible_keys为空,我做了一个糟糕的索引吗?如何让它最快?

这里是my.cnf,我的服务器有4GB内存,mysql也支持全文搜索。

我尝试将key_buffer_sizeinnodb_buffer_pool_size设置为512MB,但服务器很容易崩溃并发出警告apache child process still did not exit sending a sigterm。我必须为系统和apache留下至少1GB内存吗? (my.cnf只有2.5-3GB左右?)

[mysqld]
character_set_server=utf8
port        = 3306
socket      = /var/lib/mysql/mysql.sock
skip-external-locking
skip-networking
key_buffer = 256M
tmp_table_size = 64M
max_connections = 300
wait_timeout=15
back_log = 2048
key_buffer_size = 384M
max_allowed_packet = 2M
table_cache = 2048
table_open_cache = 2048
sort_buffer_size = 6M
read_buffer_size = 4M
net_buffer_length = 92K
read_rnd_buffer_size = 4M
myisam_sort_buffer_size = 256M
thread_cache = 384
query_cache_size= 256M
bulk_insert_buffer_size = 192M
ft_min_word_len=2
skip-networking

binlog_format=mixed

innodb_buffer_pool_size = 384M
innodb_buffer_pool_instances=4

innodb_use_sys_malloc = 0

[mysqldump]
quick
max_allowed_packet = 8M

[mysql]
no-auto-rehash

[myisamchk]
key_buffer_size = 96M
sort_buffer_size = 96M
read_buffer = 3M
write_buffer = 3M

2 个答案:

答案 0 :(得分:1)

您的实际问题是MySQL无法使用myindex LIKE '% keywords1 %'等条件的索引。本主题在网上广泛涉及,因此我建议您寻找全文索引解决方案。您可以使用一个内部(MySQL中的索引)或外部(Sphinx,Lucene等)。

答案 1 :(得分:0)

首先,您使用的是非法分组。检查http://dev.mysql.com/doc/refman/5.0/en/group-by-extensions.html

的第一段

其次,看起来这个小组甚至没有必要,并导致你的'临时'在解释中显示

第三,(不要引用我,不是100%肯定)你的temorary tmp_table_size = 64M可能对于这个查询来说太小了,因为它在分组之前将过滤后的结果存储在内存中

第4,如果你确实需要分组,为该字符串分配一个整数,并在整数上分组。

第5,如果您有关键字,请将它们存储在item-keyword表中,并将它们与连接一起使用。由于连接会给你带来一些性能损失,但它会允许你使用索引。索引仅在您从头开始比较字符串时才起作用(因此在varchar上使用长度为6-10的索引可能与使用100长度索引一样有效)

快乐优化:)