简体   繁体   English

大表的 MySQL 查询和 LEFT JOIN

[英]MySQL query and LEFT JOIN for large table

I am trying to optimize query (below) which takes 80 minutes to execute.我正在尝试优化需要 80 分钟才能执行的查询(如下)。 :/ I have very large table prodaja with 21m rows and actual_stock with 960k rows. :/ 我有非常大的表prodaja有 21m 行和actual_stock有 960k 行。

SELECT
    p.NazivMat,
    sum(p.Kolicina) AS ProdajaKol,
    sum(p.Iznos) AS ProdajaIznos,
    s.Kolicina AS TrenutnaZaliha,
    s.Iznos AS TrenZalIznos 
FROM
    prodaja p
LEFT JOIN actual_stock s ON s.BrojSklad = p.BrojSklad 
    AND s.SifraMat = p.SifraMat 
WHERE
    p.Dobavljac = 1664 
    AND p.DatumOtprem BETWEEN '2020-12-10' 
    AND '2020-12-11'

I have set Indexes on fields BrojSklad and SifraMat but it does not change much at all as I have dates and range changing and query can take (run) forever if 10 days range is selected (with this query).我已经在字段BrojSkladSifraMat上设置了索引,但它根本没有太大变化,因为我有日期和范围更改,如果选择 10 天范围(使用此查询),查询可能会永远(运行)。

Is there any other way(s) to get same result with different query or two of them like "prefetch" and store in temp table and run another one?是否有任何其他方法可以通过不同的查询或其中两个(如“预取”)获得相同的结果并存储在临时表中并运行另一个?

Table with 20m rows is pain in the but.但是有 20m 行的表很痛苦。 :/ :/

UPDATE: 30. Dec更新:12 月 30 日

Thanks for all responds below.感谢以下所有回复。 For sake of simplicity, I've shorten the query, the long version is below.为简单起见,我缩短了查询,长版本如下。 I did add GROUP BY and the end of it, that's sorted.我确实添加了GROUP BY和它的结尾,这是排序的。

EXPLAIN SELECT
    cm_prodaja.NazivGrupe,
    cm_prodaja.Grupa,
    cm_prodaja.DatumOtprem,
    cm_prodaja.SifraMat,
    cm_prodaja.BarCode,
    cm_prodaja.SifArtOdDob,
    cm_prodaja.NazivMat, 
    sum(cm_prodaja.Kolicina) AS Kolicina,
    sum(cm_prodaja.Iznos) AS Iznos,
    IFNULL (zaliha_artikala_radnje.Kolicina, 0) AS TrenutnaZaliha,
    IFNULL (zaliha_artikala_radnje.Iznos, 0) AS TrenZalIznos
FROM
    cm_prodaja
    LEFT JOIN zaliha_artikala_radnje ON zaliha_artikala_radnje.BrojSklad = cm_prodaja.BrojSklad 
    AND zaliha_artikala_radnje.SifraMat = cm_prodaja.SifraMat 
WHERE
    cm_prodaja.Dobavljac = 1664 
    AND cm_prodaja.DatumOtprem BETWEEN '2020-08-10' 
    AND '2020-08-11'
    
    GROUP BY cm_prodaja.BrojSklad, cm_prodaja.NazivRadnje, cm_prodaja.SifraMat,
cm_prodaja.BarCode, cm_prodaja.SifArtOdDob, cm_prodaja.NazivMat,
cm_prodaja.Kolicina, cm_prodaja.Iznos, cm_prodaja.Dobavljac,
cm_prodaja.NazivDobavljaca, cm_prodaja.Proizvodjac,
cm_prodaja.NazivProizvodjaca, cm_prodaja.Grupa, cm_prodaja.NazivGrupe   

I made it a bit faster by adding missing Index on zaliha_artikala_radnje.BrojSklad and zaliha_artikala_radnje.SifraMat .我通过在zaliha_artikala_radnje.BrojSkladzaliha_artikala_radnje.SifraMat上添加缺失的索引来加快速度。

Another thing I did is enabling partitioning and I've set to "split" table by year (months) on 4 sections/year and that helped a lot.我做的另一件事是启用分区,我已经设置为每年(月)在 4 个部分/年上“拆分”表,这有很大帮助。

I've added image with EXPLAIN result.我添加了带有 EXPLAIN 结果的图像。

查询 EXPLAIN 结果

Add these composite indexes, with the columns in the order given:添加这些复合索引,列按给定顺序排列:

p:  (Dobavljac, DatumOtprem)
s:  (SifraMat, BrojSklad, Iznos, Kolicina)

If you need further assistance, please provide SHOW CREATE TABLE and fix the syntax error: ... LEFT The JOIN...如果您需要进一步帮助,请提供SHOW CREATE TABLE并修复语法错误: ... LEFT The JOIN...

What is the datatype of DatumOtprem ? DatumOtprem的数据类型是什么? I am worried about the endpoints of the BETWEEN .我担心BETWEEN的端点。

Another problem... The query has SUM() , but no GROUP BY ;另一个问题...查询有SUM() ,但没有GROUP BY what is the intent?意图是什么?

thanks for suggestions.感谢您的建议。 I ended up with using PHP way to JOIN data described here: https://www.koolreport.com/docs/processes/join/我最终使用 PHP 方式来加入此处描述的数据: https://www.koolreport.com/docs/processes/join/

My original query took 3-40 minutes to give results for 1-7 days selected in filter.我的原始查询需要 3-40 分钟才能给出过滤器中选择的 1-7 天的结果。 Now it takes 2-5 seconds, where final result has 1k - 8k rows.现在需要 2-5 秒,最终结果有 1k - 8k 行。

I did try different methods and anything what has JOIN inside query dropped performance drastically.我确实尝试了不同的方法和任何在查询中加入的东西都大大降低了性能。 As said, KoolReport JOIN function solved my problem.如前所述,KoolReport JOIN function 解决了我的问题。 I created two queries, both of them are getting their sets of data ordered by SifraMat and match same field Dobavljac.我创建了两个查询,他们都得到了由 SifraMat 排序的数据集并匹配相同的字段 Dobavljac。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM