1

我使用 jQuery 创建了一个 DropDown 自动完成菜单。主要思想是,一旦将密钥插入文本框(最少 3 个字符),该函数就会使用 GET 方法将请求发送到不同的页面(比如说:search.php?q=iron man 3)和页面(search.php?q=iron man 3)。 php) 使用 MySQL 和 PHP 5 创建结果并显示它们。

到这里为止似乎还可以,但是由于我的网站上有很多用户(每天大约 10,000 个用户),每次他们点击一个键都需要一个查询,它会在服务器上造成大量过载。这会减慢服务器速度。

有没有更聪明的方法来做下拉自动完成菜单?

谢谢你。

4

3 回答 3

3

简化查询

我假设您已经规范化并简化了您正在查询的表。最好只查询一个表,该表有一个名称字段,一些分数(例如流行度)用于排名结果(如果适用),可能是一个movie_id,用于将您链接到实际电影数据或您正在查询的任何内容,也许还有一个什么类型的数据(演员、电影等)的标识符。

您不必对所有内容进行规范化,将这些数据移动到单独的表中并在每次想要查看名称时运行连接。这可能只是数据的额外副本。您甚至可以使用通常不会使用的存储引擎,例如内存或 MyISAM(请参阅下面的文本搜索)来提高性能。

减少查询流量

添加是在运行查询时添加一些条件。不要运行查询,直到他们在短时间内停止输入(0.5+ 秒左右与默认的 0.3 秒)。这将是您提高服务器稳定性的最简单、最快捷的方法,但会牺牲响应性,因为它们必须停止更长时间。您也可以尝试避免客户端同时运行多个查询,这对读者来说是一个练习,但是如果有适当的延迟,这可能是无用的。如果您从 Google 来到这里,您可以在http://docs.jquery.com/UI/API/1.8/Autocomplete查看相应的 jquery 自动完成文档。

$( ".selector" ).autocomplete({
    minLength: 3, // already set
    delay: 500
});

使用文本搜索引擎

另一个改进是使用文本搜索引擎。MySQL 使用 MyISAM 和 InnoDB(5.6 中的新功能)引擎进行了一些全文搜索,但 MyISAM 有一些权衡,并且 InnoDB 全文可能无法提供生产就绪的结果(如此处所示)。幸运的是,在 MySQL 中切换表类型相当容易,并且拥有一个仅包含名称副本的小表应该可以缓解任何问题。有些数据库让您自己重建所有内容以进行更复杂的 DBA 操作。

如果您的网站变得足够繁忙,那么一个专门的搜索引擎可能是个好主意,例如Lucene / CLucene(一个 c++ 端口)、Solr(Lucene 子项目)、SphinxXapian等等。

替代方法

关于我看到的唯一真正的替代方法是将整个数据集推送给每个访问者,并让客户端在 javascript 中自行处理查询和结果。对于 HTML5 应用程序,这可能有一些用途,但请确保数据被缓存。

于 2013-05-06T16:04:06.773 回答
2

这取决于你所说的聪明。

你想减少你的服务器负载,可以做一些事情:

设置更长的延迟。

这是您可以做的最简单的事情之一。可以通过delay参数减少查询次数:

$( ".selector" ).autocomplete({
    delay: 500 
});

默认值为300毫秒,您可能需要设置更多。

设置 minLength

另一件容易做的事情是设置在查询开始之前需要插入的最小长度。将其设置为大于一的数字。根据你的口味调整它。

$( ".selector" ).autocomplete({
    delay: 500, //from before
    minLength: 3
});

优化您的查询。

您说是您的应用程序中最消耗资源的部分。确保您的查询尽可能优化。根据数据库,可以搜索最佳实践。确保只查询最少量的所需数据。如果要为自动完成显示最多 5 个结果,只查询 5 条记录。(在 MySQL 中有,LIMIT但我听说也可以优化)。

索引

好地方的索引可以大大提高您的查询速度。例如看这篇文章。

缓存表。

如果您查询许多连接在一起的表,请考虑制作一个非常简单的表,其中只存储自动完成的可能值。这样你的查询会简单得多。不过,您需要事先填充它。

于 2013-05-06T16:06:33.210 回答
0

我的原子防火墙将我的自动完成脚本标记为 DDOS 攻击我进入了 jquery 自动完成脚本并对其进行了更改,因此它 1)仅查找 3 个字母然后创建一个列表 2)仅在未发送查询时进行查询 这可能不是最好的方法,但它阻止了所有的防火墙问题,并降低了我的服务器负载,不会发出高负载警告,可能会减少 80%

function request(term, success, failure) {
    if (!options.matchCase)
        term = term.toLowerCase();
    var data = cache.load(term);
    // recieve the cached data
    if (data && data.length) {
        success(term, data);
    // if an AJAX url has been supplied, try loading the data now
    } else if( (typeof options.url == "string") && (options.url.length > 0) ){

        var extraParams = {
            timestamp: +new Date()
        };
        $.each(options.extraParams, function(key, param) {
            extraParams[key] = typeof param == "function" ? param() : param;
        });
        // added by gary - the ajax call is made at 3 letters and only 1 call is made to avoid swamping the server with ajax requests


        if(term.length>'3'){
        stopLoading();
        }
        if(term.length=='3'){  // added by gary
        var calls=$("#AUTOCOMPLETECALLS").val();
        if(calls==0){ //by pass if a call already made
        $.ajax({
            // try to leverage ajaxQueue plugin to abort previous requests
            mode: "abort",
            // limit abortion to this input
            port: "autocomplete" + input.name,
            dataType: options.dataType,
            url: options.url,
            data: $.extend({
                q: lastWord(term),
                limit: options.max
            }, extraParams),
            success: function(data) {

                var parsed = options.parse && options.parse(data) || parse(data);
                cache.add(term, parsed);
                success(term, parsed);
                var numCalls=$("#AUTOCOMPLETECALLS").val();
                numCalls++;
                $("#AUTOCOMPLETECALLS").val(numCalls);
                var idData = $(input).attr('id');
                if(idData=='txtText'){
                var SplitData=data.split("|");
                if(SplitData[1]==undefined){
                    if(document.getElementById('donor_id') != null)
                    {
                        $("#donor_id").val('0');
                        $("#NewRecepientWarning").show();
                    }   
                } }

            } 
        });
        } // eof calls
        } else {                         //eof term.length
            // no match is selected the user just keeps typing
            hideResultsNow();
            var idData = $(input).attr('id');
            if(idData=='txtText'){
            if(document.getElementById('donor_id') != null)
            {
                $("#donor_id").val('0');
                $("#NewRecepientWarning").show();
            } }

        }
    } else {
        // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
        select.emptyList();
        failure(term);

    }
};    
于 2015-03-03T18:04:10.490 回答