2017-02-19 70 views
0

我有以下查询,它总是使整个网站下载下来的,原因是其的“等待表级锁”:MySQL的性能:一个大的查询总是卡住/慢

/*IPS\Patterns\_ActiveRecordIterator::count:246*/ SELECT SQL_CALC_FOUND_ROWS forums_posts . * , forums_topics . * 
FROM `forums_posts` 
LEFT JOIN `forums_topics` ON forums_posts.topic_id = forums_topics.tid 
LEFT JOIN `core_permission_index` ON core_permission_index.app = 'forums' 
AND core_permission_index.perm_type = 'forum' 
AND core_permission_index.perm_type_id = forums_topics.forum_id 
LEFT JOIN `forums_forums` ON forums_topics.forum_id = forums_forums.id 
WHERE (
NULLIF(forums_topics.moved_to, '') IS NULL 
) 
AND (
forums_forums.password IS NULL 
OR (
(
FIND_IN_SET(2, forums_forums.password_override) 
) 
) 
) 
AND (
forums_forums.can_view_others =1 
OR forums_topics.starter_id IS NULL 
) 
AND forums_forums.min_posts_view <=0 
AND queued =0 
AND forums_topics.approved =1 
AND (
(
(
FIND_IN_SET(2, perm_2) 
) 
) 
OR perm_2 = '*' 
) 
ORDER BY post_date DESC 
LIMIT 185725 , 25 

有什么我可以做改善这个查询的性能,而不是杀死进程/等待10分钟直到它完成?

+0

那是因为[SQL_CALC_FOUND_ROWS](http://stackoverflow.com/questions/186588/which-is-fastest-select-sql-calc-found-rows-from-table-or-select-count) – Fal

回答

0

如果这是一个“爬虫”,正在打开你的网站,你真的必须摆脱OFFSET的使用。或者获取一些过滤器来防止有效的DOS(拒绝服务)攻击。至少告诉搜索机器人,以避免您的网站。 (这可能是简单的答案。)

让我们变得真实。 LIMIT 185725 , 25 - 这是第7429页。你真的穿过那么多页吗?

你有那么多行,但没有方便的方式来“搜索”或“巩固”数据?

其他问题:

OR是昂贵的 - 它可以防止索引使用

LEFT JOIN往往需要寻找到“正确”的表,但快乐的时候无所不有。这可能比普通的JOIN更糟糕。 (然而,业务逻辑可能需要它。)

由于查询的复杂性,SQL_CALC_FOUND_ROWS可能需要几乎与获取所有没有LIMIT的行一样长的时间。注意搜索引擎过去常常说“约180,000”的结果,然后甚至放弃了这一结果。也许你的应用程序应该这样做。

当然有一个更简单的方法来做NULLIF(forums_topics.moved_to, '') IS NULL

你使用什么引擎表?如果使用MyISAM,切换到InnoDB;那可能会摆脱“表级锁定”。

0

请检查表类型是InnoDB。如果是MyISAM,则将其转换为InnoDB。 MyISAM无法读取表中的数据,而其他某个线程/查询正在更新该表中的任何行。它使用表级锁。

InnoDB使用MVCC在UPDATE/INSERT/DELETE更新表时启用SELECT。