【问题标题】:SQL need to improve run speedSQL需要提高运行速度
【发布时间】:2017-12-12 15:42:43
【问题描述】:

我正在尝试通过数据库中的日期字段从 mysql 中选择数据。 (用户可以输入开始日期和结束日期)

对于用户选定日期之间的每个选定行,我需要从同一个表中进行选择以产生结果。

例子:

    $query = "SELECT * FROM table WHERE date BETWEEN $begindate AND $enddate"; //Select by date
    $result = mysqli_query($dbc,$query);
    while($row = mysqli_fetch_array($result)){
        vardump($row); //user needs to see all data between date selection
        $query = "SELECT * FROM table WHERE field = $row['field']";
        // and then do calculations with the data
    }

这运行得很慢,我明白为什么。如何提高运行速度?

编辑: 最初的目的是在日期之间生成销售报告。现在用户希望报表产生另一个结果。此结果只能通过搜索同一个表来产生,并且我需要的行不在日期选择范围内。

编辑 2: 我确实需要在日期选择之间输出整个表格。每行都需要在日期选择的内部或外部找到 field = field 的所有其他行。

编辑 3:解决了问题。尽管我认为所选答案与我的问题最相关,但所有答案都很有帮助。但是,我相信在处理两个表时使用 join 是正确的方法。对于我的问题,我实际上只是通过复制表格并针对复制的表格运行搜索来解决它。选择的答案对我不起作用,因为第二个查询选择不是第一个查询选择的一部分。希望这会帮助任何看到这篇文章的人。再次感谢所有帮助!

【问题讨论】:

  • 你的表有索引吗?
  • 为什么要对表运行单个查询循环?
  • 查看 SQL 中的 JOIN 语法,以便您可以运行 ONE 查询以在一次执行中获取所有数据。我假设您正在查看两个不同的表,对吗?
  • 对表和字段使用有意义的名称。两个查询是同一张表吗?
  • Codemole 的答案应该可以完成您需要做的事情,而无需复制表格。尽管 Tony Chiboucas 建议的加入也应该有效并且是我的选择。进行自联接并从两个匹配行返回数据都不是问题。

标签: php mysql sql query-optimization


【解决方案1】:

好吧,所以如果你真的在同一张表中寻找这样的条件,我建议你应该使用IN选择器,如下所示:

$query = "SELECT * FROM table 
           WHERE field IN 
               (SELECT DISTINCT field FROM table 
                WHERE 
                    date BETWEEN $begindate AND $enddate)";

所以最终代码如下所示:

    $query = "SELECT * FROM table 
           WHERE field IN 
               (SELECT DISTINCT field FROM table 
                WHERE 
                    date BETWEEN $begindate AND $enddate)";
    $result = mysqli_query($dbc,$query);
    while($row = mysqli_fetch_array($result)){
        // do calculations with the $row
    }

【讨论】:

  • 即使 OP 使用同一张表,您也可以进行连接
  • @RiggsFolly 请解释一下。这可能是我正在寻找的。​​span>
  • 我会提议将内部查询简化为 SELECT DISTINCT 并删除 group by.. 相同的结果,但更容易澄清每个“字段”的单个记录。很好的答案,并且会在外部查询按字段排序时关闭,然后日期可能会递减,因此 PHP 输出不必再对数据进行排序。不过答案很好。
  • @RiggsFolly 因为是一张表,取决于表数据,加入不是一个好的选择。尤其是当字段中有许多相同的数据时,连接可能会运行缓慢。
  • @PenPen 我相信这个答案将是您正在寻找的正确答案。
【解决方案2】:

我猜你的表名不是TABLE:

只是用户inner join

 $query = "SELECT * 
           FROM table1
           JOIN table2 
             ON table1.field = table2.field
           WHERE date BETWEEN $begindate AND $enddate
           ORDER BY table1.field;"

【讨论】:

    【解决方案3】:

    停止编写伪SQL

    SELECT * FROM在技术上是伪SQL(解释器必须修改后才能执行命令的sql命令。最好养成specifying columns in the SELECT statement的习惯。

    使用SQL joins

    连接是关系数据库如此有用和强大的原因。学习它们。爱他们。

    您的一组 SQL 查询,合并为一个查询:

    SELECT 
        table1.id as Aid, table1.name as Aname, table1.field as Afield,
        table2.id as Bid, table2.name as Bname, table2.field 
    FROM table table1
    LEFT JOIN table table2 
        ON table1.field = table2.field
    WHERE table1.date BETWEEN $begindate AND $enddate
    ORDER BY table1.id, table2.id
    

    您对数据的打印结果应该会导致访问每组数据的内容类似于:

    $previous_table1_id = 0;
    while($row = mysqli_fetch_array($result)){
        if ($row['Aid'] != $previous_table1_id) {
            echo 'Table1: ' . $row['Aid'] . ' - ' . $row['Aname'] . ' - '. $row['Afield'] . "\n";
            $previous_table1_id = $row['Aid'];
        }
    
        echo 'Table2: ' . $row['Bid'] . ' - ' . $row['Bname'];
    }
    

    处理汇总数据

    数据聚合(field 上的 table1/table2 的多个匹配项)是一个复杂的主题,但了解这一点很重要。现在,我将把这个留给你:

    以下是聚合数据之一的简化​​示例,以及使用它的无数方法之一。

    Contents of Table
    id |  name  |  field
    --------------------
    1  |  foos  |  whoag 
    2  |  doh   |  whoag
    3  |  rah   |  whoag
    4  |  fun   |  wat
    5  |  ish   |  wat
    
    Result of query I gave you
    Aid | Aname | Afield | Bid | Bname
    ----------------------------------
    1   | foos  | whoag  | 1   | foos
    1   | foos  | whoag  | 2   | doh
    1   | foos  | whoag  | 3   | rah
    2   | doh   | whoag  | 1   | foos
    2   | doh   | whoag  | 2   | doh
    2   | doh   | whoag  | 3   | rah
    3   | rah   | whoag  | 1   | foos
    3   | rah   | whoag  | 2   | doh
    3   | rah   | whoag  | 3   | rah
    4   | fun   | wat    | 4   | fun
    4   | fun   | wat    | 5   | ish
    5   | ish   | wat    | 4   | fun
    5   | ish   | wat    | 5   | ish
    

    GROUP BY 收缩结果集示例

        SELECT table1.id as Aid, table1.name as Aname
               group_concat(table2.name) as field
        FROM table table1
        LEFT JOIN table table2 
            ON table1.field = table2.field
        WHERE table1.date BETWEEN $begindate AND $enddate
        ORDER BY table1.id, table2.id
        GROUP BY Aid
    
    Aid | Aname | field
    ----------------------------------
    1   | foos  | foos,doh,rah
    2   | doh   | foos,doh,rah
    3   | rah   | foos,doh,rah
    4   | fun   | fun, ish
    5   | ish   | fun, ish
    

    【讨论】:

    • 感谢您的帮助!我没有使用两张桌子。我需要搜索表格本身。
    • @PenPen,这就是加入的作用。加入对自身的表。 From table table1 为您的“表格”创建一个“别名”。这样就完成了自连接。你可以自己尝试一个简单的查询:SELECT DISTINCT(a.field) as Afield FROM table a;
    • @PenPen,请尝试将其插入您的 PhpMyAdmin 或 MySql 控制台:SELECT a.*, b.* FROM table a LEFT JOIN table b ON a.field = b.field。然后你至少可以看到你正在使用的数据。
    猜你喜欢
    • 2017-11-03
    • 2019-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多