mysql查询耗时太长

时间:2013-04-11 22:42:38

标签: mysql

我是高级查询的新手,所以我可能有一些概念上的错误,因为当数据库有超过100万条记录时,我得到了这个回复我的查询......

ERROR 2013: Lost connection to MySQL server during query

是的!它实际上需要很长时间才能在它完成之前呕吐。

我的疑问是......

SELECT users.username,
    table_1.field_abc, table_1.field_def,
    table_2.field_ghi, table_2.field_jkl
FROM users
LEFT JOIN table_1 ON table_1.username = users.username
LEFT JOIN table_2 ON table_2.username = users.username
WHERE
    table_1.field_abc REGEXP "(spork|yellow)" OR
    table_1.field_def REGEXP "(spork|yellow)" OR
    table_2.field_ghi REGEXP "(spork|yellow)" OR
    table_2.field_jkl REGEXP "(spork|yellow)"
GROUP BY users.username
ORDER BY
(
    ( CASE WHEN table_1.field_abc LIKE "%spork%" THEN 1 ELSE 0 END ) +
    ( CASE WHEN table_1.field_abc LIKE "%yellow%" THEN 1 ELSE 0 END ) +
    ( CASE WHEN table_1.field_def LIKE "%spork%" THEN 1 ELSE 0 END ) +
    ( CASE WHEN table_1.field_def LIKE "%yellow%" THEN 1 ELSE 0 END ) +
    ( CASE WHEN table_2.field_ghi LIKE "%spork%" THEN 1 ELSE 0 END ) +
    ( CASE WHEN table_2.field_ghi LIKE "%yellow%" THEN 1 ELSE 0 END ) +
    ( CASE WHEN table_2.field_jkl LIKE "%spork%" THEN 1 ELSE 0 END ) +
    ( CASE WHEN table_2.field_jkl LIKE "%yellow%" THEN 1 ELSE 0 END )
)DESC;

我在http://sqlfiddle.com/#!2/cbbda/28

发布了一个示例数据集(只有几条记录)

sqlfiddle上的示例运行速度很快,因为只有少量记录,但我尝试在我自己的服务器上复制记录,查询只用几条记录快速运行,而且在我添加了一百万条记录后速度非常慢。

有没有办法快速获得我的结果?

6 个答案:

答案 0 :(得分:1)

好伙计......在你的帮助下,我们有了解决方案...见http://sqlfiddle.com/#!2/fcfbd/5 但我仍然有一个问题...

我改变了表格以添加索引......

ALTER TABLE  `users` ADD FULLTEXT ( `username` );
ALTER TABLE  `table_1` ADD FULLTEXT ( `field_abc`,`field_def` );
ALTER TABLE  `table_2` ADD FULLTEXT ( `field_ghi`,`field_jkl` );

然后我接受了@Barmar的建议并将代码改为此...

SELECT users.username,
    table_1.field_abc, table_1.field_def,
    table_2.field_ghi, table_2.field_jkl
FROM users
LEFT JOIN table_1 ON table_1.username = users.username
LEFT JOIN table_2 ON table_2.username = users.username
WHERE
    MATCH(table_1.field_abc,table_1.field_def,table_2.field_ghi,table_2.field_jkl)
    AGAINST ("spork yellow" IN BOOLEAN MODE)
GROUP BY users.username
ORDER BY
(
    ( CASE WHEN MATCH(table_1.field_abc) AGAINST ("spork" IN BOOLEAN MODE) THEN 1 ELSE 0 END ) +
    ( CASE WHEN MATCH(table_1.field_abc) AGAINST ("yellow" IN BOOLEAN MODE) THEN 1 ELSE 0 END ) +

    ( CASE WHEN MATCH(table_1.field_def) AGAINST ("spork" IN BOOLEAN MODE) THEN 1 ELSE 0 END ) +
    ( CASE WHEN MATCH(table_1.field_def) AGAINST ("yellow" IN BOOLEAN MODE) THEN 1 ELSE 0 END ) +

    ( CASE WHEN MATCH(table_2.field_ghi) AGAINST ("spork" IN BOOLEAN MODE) THEN 1 ELSE 0 END ) +
    ( CASE WHEN MATCH(table_2.field_ghi) AGAINST ("yellow" IN BOOLEAN MODE) THEN 1 ELSE 0 END ) +

    ( CASE WHEN MATCH(table_2.field_ghi) AGAINST ("spork" IN BOOLEAN MODE) THEN 1 ELSE 0 END ) +
    ( CASE WHEN MATCH(table_2.field_ghi) AGAINST ("yellow" IN BOOLEAN MODE) THEN 1 ELSE 0 END )
)DESC;

在我的真实数据库中有超过1,000,000条记录,我的结果是6.5027秒。那比A ...好多了,花了很长时间才发现它!

我现在唯一的问题是......为什么它只适用于IN BOOLEAN MODE而不是http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html#function_matchhttp://dev.mysql.com/doc/refman/5.5/en/fulltext-search.html中提到的其他两个选项?

答案 1 :(得分:0)

我不这么认为 - 有了这张桌子,我怀疑你会让它们快速运行所有这些LIKE。那些必须经历荒谬的次数。

如果这些值是固定的,那么您可以向名为abc_like_yellowabc_like_spork等的表添加新列,并将这些值填充一次,然后您可以轻松查询该列

但如果你想动态地做这件事,你可能会运气不好。

答案 2 :(得分:0)

由于我们加入了username,因此此列上的索引可能会加快速度。

此外,您是否可以使用内部联接而不是左联接?这也可以在很大程度上加快查询速度。

最后,如果有必要,可以在内存中完成排序,而不是要求数据库执行此操作(即在返回结果集后对其进行排序)。

答案 3 :(得分:0)

我正在使用我的第一个解决方案,但发现它给出了一些我无法弄清楚的误报,所以我想出了这个......

(SELECT username, MATCH(field_abc,field_def) AGAINST ("spork yellow" IN BOOLEAN MODE) AS score FROM table_1 HAVING score>0)
UNION ALL
(SELECT username, MATCH(field_ghi,field_jkl) AGAINST ("spork yellow" IN BOOLEAN MODE) AS score FROM table_2 HAVING score >0)

由于每个记录都是单独返回的,我无法使用GROUP BY我在查询完成后添加了这个PHP代码:

while($row = mysql_fetch_array($result) )
{
    if( in_array($row['username'],$usernames) )
    {
        $usernames_count[$row['username']] += $row['score'];
    }
    else
    {
        array_push($usernames,$row['username']);
        $usernames_count[$row['username']]=$row['score'];
    }
}
arsort($usernames_count); // Sort the results high->low

foreach($usernames_count as $key=>$value)
{
    echo "Username: ".$key." had a score of ".$value." in the search results<br/>";
}

与我做的其他尝试相比,它现在看起来很简单。

答案 4 :(得分:0)

当您的服务器必须扫描数百万条目时,它可能不够强大,无法快速处理查询。

一般来说,为了提高网站的速度,您可以尝试CloudFlare

如果您专门尝试加速SQL,Google Cloud SQL可能会有所帮助。 Google功能强大的服务器旨在扫描数十亿条SQL条目,例如执行Google搜索时。

只要没有返回错误,上述两项服务将有助于大大加快您的查询时间。

我希望我能帮忙!

VCNinc

答案 5 :(得分:0)

如果您有权访问SQL Server,请在SQL Server中突出显示您的完整查询,然后单击+ L

这将显示查询执行计划。根据这些结果优化查询;

例如,如果您看到表扫描,那么索引可能会有所帮助。  编写不使用术语distinct的查询。  如果订单不重要,请不要订购结果。

在您的样本中,复杂的最后一组订单非常昂贵。

请按照以下步骤操作:  将核心信息拉入临时表,其中包含9个额外列(类型为int,最初设置为0)  填充核心数据后,根据0或1条件更新8列中的每一列  将最后一列更新为其他8列的总和  从表中检索信息,只有一个基于第9列的“订单”。

根据我的经验,与在内部执行订单相比,这种方法只需要20%的时间。

相关问题