【问题标题】:How to improve SQL query speed on Date in a larger Database如何提高大型数据库中日期的 SQL 查询速度
【发布时间】:2021-04-24 17:54:25
【问题描述】:

我正在尝试优化 SQL 查询以提高其执行速度。我已经发现 Date 列是问题所在。当我运行此查询时,包括数据库中的日期:

SELECT p.*, preis.preis
FROM produkt p INNER JOIN (SELECT * FROM preis WHERE DATE(preis.Datum) = CURDATE()) preis ON p.id = preis.produkt_id
WHERE artikel_id IN (SELECT artikel_id FROM produkt WHERE haendler_id = 1)

需要 28 秒才能得到结果。但是当我将 INNER JOIN 选择的 WHERE-Clause 更改为 id > 256981 时,我得到相同的结果,它只需要 0,062 秒。

SELECT p.*, preis.preis
FROM produkt p INNER JOIN (SELECT * FROM preis WHERE preis.id > 256981) preis ON p.id = preis.produkt_id
WHERE artikel_id IN (SELECT artikel_id FROM produkt WHERE haendler_id = 1)

这是一个很大的不同。

我已经阅读了一些关于 INDEX 和不同 INDEX 类型的内容,但是我找不到以正确方式对 DATE 字段进行 INDEX 的解决方案。 或者还有其他方法可以改进这样的查询吗?

【问题讨论】:

  • 那么在日期列上创建索引有什么问题呢?
  • @ClausBönnhoff 我在日期字段中添加了一个普通索引,但它不影响查询时间,仍然需要大约 28 秒。所以我问我是否需要一个特殊的日期列
  • 在查询之前创建一个今天的日期,然后像 WHERE preis.Datum = '2021-01-20' 一样使用它

标签: mysql sql join indexing


【解决方案1】:
SELECT  p.*, q.preis
    FROM  ( SELECT artikel_id FROM produkt WHERE haendler_id = 1 ) AS a
    JOIN produkt p USING(artikel_id)
    INNER JOIN  
        ( SELECT  preis
            FROM  preis
            WHERE  Datum >= CURDATE()
               AND Datum  < CURDATE() + INTERVAL 1 DAY
        ) AS q  ON p.id = q.produkt_id

并且有这些索引:

preis:  INDEX(Datum, produkt_id, preis)
preis:  INDEX(produkt_id, Datum, preis)
produkt:  INDEX(haendler_id, artikel_id)
produkt:  INDEX(artikel_id)

如果产品只能有一个preis,那么还有另一种选择。

我们确实需要查看SHOW CREATE TABLE——检查数据类型、主键和其他内容。

【讨论】:

  • 谢谢!您的查询会在 1 秒内打印出正确的数据。但我真的不明白为什么..
  • @Peacycode - 我所做的一些事情......我重新排列了 3 个表,试图思考如何手动解决问题:首先是获取一个 artikel_id;最后是检查preis。订单帮助我理解查询;如果选择,优化器将重新排列表格。至于索引,见mysql.rjweb.org/doc.php/index_cookbook_mysql
【解决方案2】:

我相信您的 id 列上有索引,但数据列上没有索引,请在该列上定义索引,您应该会得到几乎相同的结果。

【讨论】:

    【解决方案3】:

    首先,不要使用子查询。其次,我也不推荐in。所以:

    SELECT p.*, pp.preis
    FROM produkt p INNER JOIN
         preis pp
         ON p.id = pp.produkt_id
    WHERE p.Datum >= CURDATE() AND
          p.Datum < CURDATE() + INTERVAL 1 DAY AND
          EXISTS (SELECT 1
                  FROM produkt p2
                  WHERE p2.artikel_id = p.artikel_id AND
                        p2.haendler_id = 1
                 );
    

    那么对于这个查询,您需要product(artikel_id, haendler_id) 和preis(Datum, product_id) 上的索引。

    【讨论】:

    • 您的回答将查询时间缩短了大约 10 秒。我现在发现提取时间大约是 18 秒。
    • @Peacycode 。 .那么它一定是在检索大量数据。
    【解决方案4】:

    主要问题是当您使用 mysql 时,任何构建函数(如 CURDATE())都会使查询变慢,因此请尽量避免使用它,因此请尝试像这样更新您的查询

    // first make today date if your code is php then $today = date('Y-m-d');
    then use this in mysql 
    SELECT p.*, preis.preis
    FROM produkt p INNER JOIN (SELECT * FROM preis WHERE DATE(preis.Datum) = '$today') 
    preis ON p.id = preis.produkt_id
    WHERE artikel_id IN (SELECT artikel_id FROM produkt WHERE haendler_id = 1)
    

    最好避免DATE

    SELECT p.*, preis.preis
    FROM produkt p INNER JOIN (SELECT * FROM preis WHERE preis.Datum = '$today') 
    preis ON p.id = preis.produkt_id
    WHERE artikel_id IN (SELECT artikel_id FROM produkt WHERE haendler_id = 1)
    

    我想这会对你有所帮助

    【讨论】:

    • 我尝试了第一个查询,它改进了大约几秒钟的时间,但仍然超过 20 秒。第二个查询不给我一列。
    • 可能你的 Datum 是日期时间列,所以需要 DATE 函数,所以第二个不起作用
    • @ShafiqulIslam - CURDATE() 和 NOW() 一样,在优化方面实际上是一个常数。 DATE(column) 不是。
    【解决方案5】:

    您是否尝试过直接在datum上使用不带子查询和条件的join,不带日期功能如下:

    SELECT p.*, preis.preis
      FROM produkt p 
     INNER JOIN preis ON p.id = preis.produkt_id
    WHERE preis.Datum >= CURDATE() and preis.Datum < DATE_ADD(CURDATE(), INTERVAL 1 DAY)
      AND artikel_id IN (SELECT artikel_id FROM produkt WHERE haendler_id = 1)
    

    您可以在preis.Datum 上创建索引,如下所示:

    CREATE INDEX preis_indx_01 ON preis(Datum);
    

    注意:如果produkt_id经常用于join,也可以考虑创建索引。

    【讨论】:

    • 感谢您的回答!查询时还需要 28 秒。我像你一样创建了索引,但它也不影响查询。如果 produkt_id 是外键还没有被索引?
    • 创建我在答案中创建的索引并从答案中执行查询。不是来自问题的查询。外键没有索引。您必须在其上创建索引。
    • 我现在已经索引了日期和外键,但是当我点击你的查询时没有任何改变。
    • 你应该会看到解释计划。
    • @Peacycode - 请提供SHOW CREATE TABLE,以便我们查看哪些内容已编入索引,哪些内容未编入索引。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 2011-09-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多