5

我是高级查询的新手,所以我可能在概念上有些错误,因为当数据库有超过 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 的示例运行速度很快,因为只有几条记录,但我尝试在我自己的服务器上复制记录,查询运行速度很快,只有几条记录,在添加一百万条记录后速度非常慢。

有什么方法可以快速得到我的结果吗?

4

6 回答 6

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 秒内得到了结果。这比……好很多,花了很长时间才吐出来!

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

于 2013-04-12T00:14:01.427 回答
0

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

另外,你能使用内连接而不是左连接吗?这也可以在很大程度上加快查询速度。

最后,如果需要,可以在内存中进行排序,而不是要求数据库进行排序(即在返回结果集后对结果集进行排序)。

于 2013-04-11T22:52:03.237 回答
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/>";
}

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

于 2013-04-12T18:31:53.047 回答
0

我不这么认为——用这张桌子原样,我怀疑你会把所有这些都LIKE放在上面。那些必须运行荒谬的次数。

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

但是,如果您尝试动态执行此操作,则可能会不走运。

于 2013-04-11T22:47:59.117 回答
0

当您的服务器必须扫描数百万个条目时,它的功能可能不足以快速处理查询。

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

如果您特别想加快 SQL 速度,Google Cloud SQL可能会有所帮助。Google 强大的服务器旨在扫描数十亿条 SQL 条目,例如在执行 Google 搜索时。

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

我希望我能帮上忙!

VCNinc
于 2013-05-02T05:54:55.857 回答
0

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

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

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

在您的示例中,最后一组复杂的订购方式非常昂贵。

而是遵循以下步骤: 将核心信息拉入一个临时表,在填充核心数据后有 9 个额外的列(类型 int,初始设置为 0),根据 0 或 1 标准更新 8 列中的每一列 更新最后一列作为其他 8 列的总和,从 table 中检索信息,只有一个基于第 9 列的“order-by”。

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

于 2013-05-10T11:43:11.677 回答