MySQL查询数据库以显示检查列表的最佳方法

时间:2015-11-02 15:39:37

标签: php mysql database performance

我在数据库中有4个表格,可以让我管理一种“检查清单”。对于每个pathology,只需几句话,我就有一大步(process)分为tasks的倍数。所有这些都与摘要表中的特定操作(progress.case_id)相关联。

database.pathology
+--------------+------------+
| id_pathology |    name    |
+--------------+------------+
|            1 | Pathology1 |
|            2 | Pathology2 |
|            3 | Pathology3 |
+--------------+------------+

database.process
+------------+----------+--------------+----------------+
| id_process |   name   | pathology_id | days_allocated |
+------------+----------+--------------+----------------+
| 1          | BigTask1 | 2            | 5              |
| 2          | BigTask2 | 2            | 3              |
| 3          | BigTask3 | 2            | 6              |
| ...        | ...      | ...          | ...            |
+------------+----------+--------------+----------------+

database.task
+---------+-------+------------+
| id_task | name  | process_id |
+---------+-------+------------+
| 1       | Task1 | 1          |
| 2       | Task2 | 1          |
| 3       | Task3 | 1          |
| 4       | Task4 | 2          |
| ...     | ...   | ...        |
+---------+-------+------------+

database.progress
+-------------+---------+---------+---------+------------+---------+
| id_progress | task_id | case_id | user_id |    date    | current |
+-------------+---------+---------+---------+------------+---------+
|           1 |       1 |     120 |       2 | 2015-11-02 |       1 |
|           2 |       2 |     120 |       2 | 2015-11-02 |       0 |
|           3 |       1 |     121 |       3 | 2015-11-02 |       1 |
+-------------+---------+---------+---------+------------+---------+

我必须展示类似的东西

enter image description here

我的问题是:最有效的方法是什么?

查询只有一个表(进度)显示最多,然后查询另一个表以获取不同进程和天数的名称更快吗?

也许联合功能更有效率?

或者您认为我的数据库结构不合适吗?

对于每种情况,我们可以执行大约50个任务,将当前字段转换为复选框。后台脚本也在运行。它根据剩余天数分析提供的天数,以确定此特定案例是否可能有延迟。

对于每种情况,进度表已经填充了与案例病理相关的所有任务。目前的领域始终是' 0'在开始。

我已经尝试了多种内容,例如

$result = $db->prepare("SELECT DISTINCT process_id,process.name FROM task, progress,process WHERE progress.task_id = task.id_task AND task.process_id = process.id_process AND progress.case_id = ?");     
$result->execute(array($id));
foreach($result as $row)
{
  echo "<b>".$row[1]."</b><br>";
  $result = $db->prepare("SELECT name,id_task FROM task WHERE process_id = ?");     
  $result->execute(array($row[0]));
  foreach($result as $row)
  {
      echo $row[0];
      $result = $db->prepare("SELECT user_id, date, current FROM progress WHERE progress.task_id = ? AND case_id = ?");     
      $result->execute(array($row[1], $id));
      foreach($result as $row)
      {
        if($row[2] == 0)
        {echo "<input type='checkbox' />";}
        else
        {
          echo "<input type='checkbox' checked/>";
          echo "user : ".$row[0]." date : ".$row[1]."<br>";
        }            
      }          
  }

但我很确定我做得不对。我应该更改我的数据库基础我应该使用特定的MySQL技巧吗?或者只是一个更有效的PHP处理?

1 个答案:

答案 0 :(得分:3)

就效率而言,数据库查询是您可以执行的最慢操作之一。您可以采取的任何措施来减少您的查询数量,这将大大有助于您的应用程序更快。

但更重要的是,您的应用程序需要按设计工作,这意味着开发人员需要了解正在发生的事情,数据不应该只是等待被覆盖,以及初级开发人员将在3年内负责维护这项工作,并不想将头发撕掉。

速度比慢速好。

慢慢胜过破碎。

对于您的特定问题,如果可能,永远不会在循环内部进行查询。特别是当该循环由从同一数据库中提取的数据控制时。这是一种代码气味,需要正确使用JOIN s。

SQL Join Diagrams的Google图片搜索显示了大量维恩图,其中显示了每个JOIN返回的不同类型的数据。如有疑问,通常需要LEFT JOIN s。

所以,让我们确定你的关系:

  • 病理学

    • 未在结果中使用。
    • 找到一种方法将其合并到您的查询中,因为&#34; Pathology2&#34;出现在你的模型中。
  • 过程

    • 以一对多的关系引用病理学。每个进程可以有一个病理学,但每个病理学可以有0个或更多个进程。
  • 任务

    • 以一对多关系引用任务。任务包含Process的子项。
  • 进度

    • 参考任务,以及未显示的案例和用户。在引用特定案例和用户时,进度似乎是任务的详细信息。
    • 我假设存在业务约束,其中task_id,case_id和user_id必须是唯一的...也就是说,用户1只能为任务1和案例100提供1个进度条目。
    • 除了保存Task的详细信息外,还充当Task,Case和User之间的桥梁,为这三个表提供多对多关系。由于Task是Process的直接子项,而Process是Pathology的直接子项,因此它提供了与Pathology的多对多关系。
  • 案例

    • 推断此表的存在。
    • 由Task。引用。
  • 用户

    • 推断此表的存在。
    • 由Task。引用。

基于此表结构,我们的主要分组将是Case,Pathology和User。

也就是说,如果您是登录用户,并且想要按案例查看进度,则可能需要查看以下内容:

Case 110:
    Pathology1:
        BigTask1:
            Task1: X
            Task2: []
        BigTask2:
            Task3: X
    Pathology2:
        BigTask3:
            Task4: []
Case 120:
    Pathology1:
        BigTask1: 
            Task1: []

我们希望用户ID == 1; 我们的第一次排序将基于Case 我们的第二次排序将基于病理学 我们的第三次排序将基于Process 我们最后的排序将是在任务...

因此,获得上述结果的数据将是:

+------+------------+----------+-------+----------+
| case | pathology  | process  | task  | progress |
+------+------------+----------+-------+----------+
| 110  | Pathology1 | BigTask1 | Task1 | 1        |
| 110  | Pathology1 | BigTask1 | Task2 | 0        |
| 110  | Pathology1 | BigTask2 | Task3 | 1        |
| 110  | Pathology2 | BigTask3 | Task4 | 0        |
| 120  | Pathology1 | BigTask1 | Task1 | 0        |
+------+------------+----------+-------+----------+

我们的订购&#39;子句是从最后到第一个...... ORDER BY task, process, pathology, case ...我们可以用PHP对它进行排序,但数据库比我们更好。如果您的索引设置正确,数据库可能甚至不需要排序,它只是按顺序获取它。

获取特定用户的上述数据的查询是:

SELECT
    prog.case_id AS case,
    path.name AS pathology,
    proc.name AS process,
    task.name AS task,
    prog.current AS progress
FROM
    pathology path
LEFT JOIN process proc ON path.id_pathology = proc.pathology_id
LEFT JOIN task ON task.process_id = proc.id_process
LEFT JOIN progress prog ON task.id_task = prog.task_id
WHERE prog.user_id = :userid
ORDER BY task, process, pathology, case

您的PHP可能就是

<?php

$sql = <<<EOSQL
SELECT
    prog.case_id AS case,
    path.name AS pathology,
    proc.name AS process,
    task.name AS task,
    prog.current AS progress
FROM
    pathology path
LEFT JOIN process proc ON path.id_pathology = proc.pathology_id
LEFT JOIN task ON task.process_id = proc.id_process
LEFT JOIN progress prog ON task.id_task = prog.task_id
WHERE prog.user_id = :userid
ORDER BY task, process, pathology, case
EOSQL;

$result = $db->prepare($sql);     
$result->execute(array(':userid' => $id));
$rows = $result->fetchAll(PDO::FETCH_ASSOC);

foreach ($rows as $row) {
    var_dump($row);
    // array(5) {
    //     ["case"]=>
    //     int(110)
    //     ["pathology"]=>
    //     string(10) "Pathology1"
    //     ["process"]=>
    //     string(8) "BigTask1"
    //     ["task"]=>
    //     string(5) "Task1"
    //     ["progress"]=>
    //     int(1)
    // }
}