我的论坛上的搜索帖有问题。
1)我使用explode(" ", $string);
2)我搜索tag_id
所有tag_value
包含单词的所有SELECT tag_id WHERE tag_value like '%{word}%';
- $tags_array
所有结果都添加到数组INNER JOIN
3)我创建了foreach ($tags_array as $k => $v) {
if (!empty($v)) {
$short_name = "frt_".$i++;
$inner_array[] = " INNER JOIN forum_rel_tags as ".$short_name." ON (".$short_name.".tag_id IN (".implode(", ", $v).")) ";
$more[] = " ".$short_name.".post_id = fp.post_id ";
}
}
SELECT COUNT(fp.post_id) AS total
FROM forum_categories c
JOIN forum_thread t USE INDEX (thread_id)
ON t.category_id = c.category_id
AND t.posts_limit <= 1
AND t.contest_limit <= 3
AND (t.register_limit*86400) <= 5841372
JOIN forum_auth a
ON a.auth_id = c.category_id
AND a.auth_group_id = 1
AND a.auth_type = 1
AND a.auth_visible = 1
JOIN forum_posts fp
ON fp.thread_id = t.thread_id
AND fp.post_deleted = 0
JOIN forum_rel_tags frt_0
ON frt_0.post_id = fp.post_id
AND frt_0.tag_id IN (1000 tag_id)
JOIN forum_rel_tags frt_1
ON frt_1.post_id = fp.post_id
AND frt_1.tag_id IN (200 tag_id)
JOIN forum_rel_tags frt_2
ON frt_2.post_id = fp.post_id
AND frt_2.tag_id IN (432 tag_id)
JOIN forum_rel_tags frt_3
ON frt_3.post_id = fp.post_id
AND frt_3.tag_id IN (50 tag_id)
4)最后我有类似的东西:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t ref thread_id thread_id 4 const 1 Using where; Using index
1 SIMPLE c eq_ref PRIMARY PRIMARY 4 pionas.t.category_id 1 Using index
1 SIMPLE a eq_ref auth_type auth_type 10 const,pionas.c.category_id,const 1 Using where
1 SIMPLE frt_0 range post_id,tag_id tag_id 4 NULL 372226 Using where; Using join buffer
1 SIMPLE frt_1 range post_id,tag_id tag_id 4 NULL 37787 Using where; Using join buffer
1 SIMPLE fp eq_ref PRIMARY,thread_id,post_deleted PRIMARY 4 pionas.frt_1.post_id 1 Using where
1 SIMPLE u eq_ref PRIMARY PRIMARY 4 pionas.fp.user_id 1 Using index
1 SIMPLE frt_3 range post_id,tag_id tag_id 4 NULL 23608 Using where; Using join buffer
1 SIMPLE frt_2 ref post_id,tag_id post_id 4 pionas.frt_3.post_id 296144 Using where; Using index
但是这个查询非常慢。
我可以更改哪些内容以加快速度?
EXPLAIN SELECT
CREATE TABLE `forum_auth` (
`auth_type` smallint(1) unsigned NOT NULL DEFAULT '0',
`auth_id` int(10) unsigned NOT NULL,
`auth_visible` int(10) unsigned NOT NULL,
`auth_group_id` int(10) unsigned NOT NULL,
`auth_last_post_id` int(11) unsigned NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
ALTER TABLE `forum_auth`
ADD UNIQUE KEY `auth_type` (`auth_type`,`auth_id`,`auth_group_id`);
CREATE TABLE `forum_categories` (
`category_id` int(10) unsigned NOT NULL,
`category_name` varchar(200) NOT NULL,
`category_desc` text NOT NULL,
`category_order` tinyint(2) NOT NULL,
`category_parent` int(10) unsigned NOT NULL DEFAULT '0',
`last_post_id` int(11) NOT NULL,
`total_thread` int(11) NOT NULL,
`total_posts` int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
ALTER TABLE `forum_categories`
ADD PRIMARY KEY (`category_id`);
CREATE TABLE `forum_posts` (
`post_id` int(10) unsigned NOT NULL,
`post_subject` varchar(250) NOT NULL,
`post_message` text NOT NULL,
`post_create_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`post_last_modify` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_count_modify` int(11) NOT NULL,
`post_deleted` tinyint(1) NOT NULL DEFAULT '0',
`post_ip` int(11) NOT NULL,
`user_id` int(10) NOT NULL,
`thread_id` int(10) unsigned NOT NULL,
`guest_name` varchar(100) NOT NULL,
`guest_mail` varchar(150) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
ALTER TABLE `forum_posts`
ADD PRIMARY KEY (`post_id`),
ADD KEY `thread_id` (`thread_id`),
ADD KEY `user_id` (`user_id`),
ADD KEY `post_deleted` (`thread_id`,`post_deleted`),
ADD KEY `post_create_date` (`post_create_date`),
ADD FULLTEXT KEY `post_message` (`post_message`);
CREATE TABLE `forum_rel_tags` (
`post_id` int(10) unsigned NOT NULL,
`tag_id` int(10) unsigned NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
ALTER TABLE `forum_rel_tags`
ADD UNIQUE KEY `post_id` (`post_id`,`tag_id`),
ADD KEY `tag_id` (`tag_id`);
CREATE TABLE `forum_tags` (
`tag_id` int(10) unsigned NOT NULL,
`name` varchar(150) NOT NULL,
`tag_url` varchar(150) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
ALTER TABLE `forum_tags`
ADD PRIMARY KEY (`tag_id`),
ADD UNIQUE KEY `tag_url` (`tag_url`);
CREATE TABLE `forum_thread` (
`thread_id` int(10) unsigned NOT NULL,
`thread_subject` varchar(250) CHARACTER SET utf8 NOT NULL,
`thread_desc` text CHARACTER SET utf8 NOT NULL,
`thread_create_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`thread_view` int(10) unsigned NOT NULL DEFAULT '0',
`thread_reply` int(10) unsigned NOT NULL DEFAULT '0',
`thread_ip` int(10) unsigned NOT NULL,
`last_post_id` int(11) NOT NULL,
`user_id` varchar(100) CHARACTER SET utf8 NOT NULL,
`category_id` int(10) unsigned NOT NULL,
`guest_name` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`guest_mail` varchar(150) COLLATE utf8_unicode_ci DEFAULT NULL,
`guest_can_reply` smallint(1) NOT NULL DEFAULT '0',
`thread_block` tinyint(1) NOT NULL,
`thread_sticky` tinyint(1) unsigned NOT NULL DEFAULT '0',
`posts_limit` int(2) NOT NULL DEFAULT '0',
`register_limit` int(3) NOT NULL DEFAULT '0',
`contest_limit` int(2) NOT NULL DEFAULT '0'
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
ALTER TABLE `forum_thread`
ADD PRIMARY KEY (`thread_id`),
ADD KEY `category_id` (`category_id`),
ADD KEY `thread_id` (`thread_id`,`category_id`,`posts_limit`,`register_limit`,`contest_limit`);
表
SELECT fp.*, u.username, u.rang, u.post, u.date_register, u.avatar, u.pkt, f.city
FROM forum_categories c
JOIN forum_thread t USE INDEX (thread_id)
ON t.category_id = c.category_id
AND t.posts_limit <= 1
AND t.contest_limit <= 3
AND (t.register_limit*86400) <= 5841372
JOIN forum_auth a
ON a.auth_id = c.category_id
AND a.auth_group_id = 1
AND a.auth_type = 1
AND a.auth_visible = 1
JOIN forum_posts fp
ON fp.thread_id = t.thread_id
AND fp.post_deleted = 0
JOIN forum_rel_tags frt_0
ON frt_0.post_id = fp.post_id
AND frt_0.tag_id IN (1000 tag_id)
JOIN forum_rel_tags frt_1
ON frt_1.post_id = fp.post_id
AND frt_1.tag_id IN (200 tag_id)
JOIN forum_rel_tags frt_2
ON frt_2.post_id = fp.post_id
AND frt_2.tag_id IN (432 tag_id)
JOIN forum_rel_tags frt_3
ON frt_3.post_id = fp.post_id
AND frt_3.tag_id IN (50 tag_id)
LEFT JOIN users u
ON fp.user_id=u.user_id
LEFT JOIN users_field f
ON u.user_id=f.user_id
GROUP BY fp.post_id
ORDER BY fp.post_id DESC
LIMIT 0,30;
第二次查询:
EXPLAIN SELECT fp.*, u.username, u.rang, u.post, u.date_register, u.avatar, u.pkt, f.city
FROM forum_categories c
JOIN forum_thread t USE INDEX (thread_id)
ON t.category_id = c.category_id
AND t.posts_limit <= 1
AND t.contest_limit <= 3
AND t.register_limit <= (5841372/86400)
JOIN forum_auth a
ON a.auth_id = c.category_id
AND a.auth_group_id = 1
AND a.auth_type = 1
AND a.auth_visible = 1
JOIN forum_posts fp
ON fp.thread_id = t.thread_id
AND fp.post_deleted = 0
JOIN forum_rel_tags frt_0
ON frt_0.post_id = fp.post_id
JOIN forum_tags ft_0
ON ft_0.tag_id = frt_0.tag_id
AND ft_0.tag_url like '%play%'
JOIN forum_rel_tags frt_1
ON frt_0.post_id = frt_1.post_id
JOIN forum_tags ft_1
ON ft_1.tag_id = frt_1.tag_id
AND ft_1.tag_url like '%how%'
JOIN forum_rel_tags frt_2
ON frt_1.post_id = frt_2.post_id
JOIN forum_tags ft_2
ON ft_2.tag_id = frt_2.tag_id
AND ft_2.tag_url like '%win%'
JOIN forum_rel_tags frt_3
ON frt_2.post_id = frt_3.post_id
JOIN forum_tags ft_3
ON ft_3.tag_id = frt_3.tag_id
AND ft_3.tag_url like '%to%'
LEFT JOIN users u
ON fp.user_id=u.user_id
LEFT JOIN users_field f
ON u.user_id=f.user_id
GROUP BY fp.post_id
ORDER BY fp.post_id DESC
[编辑] 你怎么看待它:
{{1}}
答案 0 :(得分:2)
假设user_id
表中users
是唯一的,则不需要LEFT JOIN to users表。
forum_rel_tags表有四个连接;似乎有可能从每个连接返回多行;并且这些行中的每一行都将得到匹配&#34;从其他联接返回的行...这是一个部分交叉产品,即相同的fp.post_id
可以&#34;计数&#34;多次。
表现不佳的最可能解释是缺乏合适的指数。
一些谓词,例如(t.register_limit*86400)<=5841372
无法对索引使用范围扫描操作... t.register_limit*86400
上的表达式必须针对每个行进行评估(不排除在在与文字进行比较之前,可以做一些其他谓词。我们通常更喜欢在谓词中引用裸列,在那里它可以做到这一点以返回等效结果......例如。
t.register_limit <= (584137/86400)
我们可以重新编写查询,删除对users表的不必要的连接,如下所示:
SELECT COUNT(fp.post_id) AS total
FROM forum_categories c
JOIN forum_thread t
ON t.category_id = c.category_id
AND t.posts_limit <= 1
AND t.contest_limit <= 3
AND (t.register_limit*86400) <= 5841372
JOIN forum_auth a
ON a.auth_id = c.category_id
AND a.auth_group_id = 1
AND a.auth_type = 1
AND a.auth_visible = 1
JOIN forum_posts fp
ON fp.thread_id = t.thread_id
AND fp.post_deleted = 0
JOIN forum_rel_tags frt_0
ON frt_0.post_id = fp.post_id
AND frt_0.tag_id IN (1000 tag_id)
JOIN forum_rel_tags frt_1
ON frt_1.post_id = fp.post_id
AND frt_1.tag_id IN (200 tag_id)
JOIN forum_rel_tags frt_2
ON frt_2.post_id = fp.post_id
AND frt_2.tag_id IN (432 tag_id)
JOIN forum_rel_tags frt_3
ON frt_3.post_id = fp.post_id
AND frt_3.tag_id IN (50 tag_id)
这使得解密查询变得更加容易,特别是在确定哪些索引可能最适合此查询方面。
... ON forum_thread (category_id, posts_limit, contest_limit, register_limit)
... ON forum_auth (auth_id, auth_group, auth_type, auth_visible)
... ON forum_posts (thread_id, post_deleted, post_id)
... ON forum_rel_tags (post_id, tag_id)
由于这些是覆盖查询的索引,我们希望EXPLAIN输出包括&#34;使用索引&#34;对于这些表。这只是某些指数的第一次削减;这些可能已经存在,或者索引中的列可能有更合适的排序。
但由于没有表格定义,包括索引和估计的基数,它不可能给出更明确的答案。
...再次
我对forum_rel_tags
表的引用之间的部分交叉产品非常怀疑。我怀疑这个查询可以返回&#34; total&#34;这比预期的要高。这只是一个怀疑,因为我没有看到任何规范(超出查询)关于应该返回什么结果。