非常慢的mysql请求+ php

时间:2015-09-27 05:11:36

标签: php mysql sql performance

意识形态是:从表格中选择所有职业。在此计算之后,有多少专业人员在其类别列中拥有该职业ID。 category列存储了逗号ID由逗号(1,2,3,420)分隔。专业表有604行。 我有以下代码:

<?php
$select_professions = mysql_query("SELECT * FROM professions");
    if(mysql_num_rows($select_professions) == "0"){
        echo"No registers in DB";
    }else{while($row_professions = mysql_fetch_assoc($select_professions)){
        $id = $row_professions['id'];

        $count_profiles = mysql_query("SELECT 
        COUNT(FIND_IN_SET(professions.id, professional.category) > 0) AS profile_numbers
                                        FROM
                                            professions
                                        INNER JOIN
                                            professional
                                        WHERE
                                            FIND_IN_SET(professions.id,professional.category) > 0
                                        AND
                                            professions.id = $id
                                        GROUP BY
                                            professions.id");
        $reg_profiles = mysql_fetch_assoc($count_profiles);
        $numProfiles = $reg_profiles['profile_numbers'];
            if($numProfiles > 4){
                $style = 'display:none';
            }else{
                $style = '';
            }
?>

我的基本问题是为什么谷歌浏览器这么慢? 将这些结果加载到整个页面需要15秒才能生成html表格。在Edge或Firefox中大约需要5秒钟。我最近听说Chrome使用了这么多内存,但我并不认为它太慢了。这是我第一次在mysql上使用FIND_IN_SET函数。这可能会减慢请求的速度吗?任何人都知道我做错了什么或如何优化?这实际上是有效的,但我们知道15秒的等待会让用户放弃或认为该页面无效。我还要说,如果我在HeidiSQL上做同样的咨询,则需要1秒钟。

2 个答案:

答案 0 :(得分:2)

我建议将其标准化:

  

“类别”列存储以逗号分隔的职业ID(1,   2,3,420)

这是n:n关系。你的布局:

professionals:
id | catgeory
12 | 1,2,4,50

professions
id | desc
1  | prof A
2  | prof B
...

字符串操作(拆分列表,规范化内部,查询结果为temp,...)是非常耗费成本的。更好:

professionals:
id | ...
12 | ..


profrelations
pid | cid
12  | 1
12  | 2
12  | 4
12  | 50

professions
id | desc
1  | prof A
2  | prof B
...

这将跳过COUNT(FIND_IN_SET(professions.id, professional.category) > 0)作为字符串操作(甚至两次):

SELECT COUNT(cid) AS profile_numbers from professionals, profrelations where
professionals.id = profrelations.pid AND profrelations.pid = $id;

等。您可以像这样重构上述查询,只要您实际上不需要专业的任何列。

您可以在表(pid, cid)中的列profrelations上添加唯一索引,因为一个专业人员实际上只能拥有一个专业一次。

<强>备注

两个浏览器中的不同行为可能来自服务器缓存查询:您正在使用Chrome进行查询,但速度很慢,但结果会被缓存。接下来使用FF,服务器将再次使用缓存的结果作为同一查询 - 快速响应。尝试三次或反过来,在所有浏览器中应该是相同的。

答案 1 :(得分:1)

起初,
此操作COUNT(FIND_IN_SET(professions.id, professional.category) > 0)不会返回您期望的结果。即使Count返回1,上述表达式中的find_in_set也会返回0
其次,我根本不会在这种情况下使用join。这些表与标识符没有直接关系 我会优化查询如下:

SELECT COUNT(professions.id) AS profile_numbers FROM professions, professional 
WHERE FIND_IN_SET(professions.id,professional.category) > 0 AND professions.id = $id 
GROUP BY professions.id