Mysql 如何使用多个and和OR优化此慢速查询

Mysql 如何使用多个and和OR优化此慢速查询,mysql,query-optimization,mysql-workbench,Mysql,Query Optimization,Mysql Workbench,我的问题是 SELECT transaktion.betrag_eur FROM transaktion_buchung AS transaktion WHERE transaktion.fk_kunde=303276 AND transaktion.konto='Cashback' AND transaktion.storniert_am IS NULL AND transaktion.freigegeben_am IS NULL AND (transaktion.

我的问题是

SELECT  transaktion.betrag_eur
FROM transaktion_buchung AS transaktion
WHERE transaktion.fk_kunde=303276 
  AND transaktion.konto='Cashback' 
  AND transaktion.storniert_am IS NULL 
  AND transaktion.freigegeben_am IS NULL  
  AND (transaktion.buchungstyp!='Zahlung' OR transaktion.buchungstyp IS NULL)
由于磁盘空间限制,此查询的密钥文件错误。如何优化此查询

“解释”将显示以下内容

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   PRIMARY <derived2>  ALL NULL    NULL    NULL    NULL    653631  Using where
2   DERIVED transaktion ALL NULL    NULL    NULL    NULL    428809  
2   DERIVED buchung ref fk_buchung_transaktion  fk_buchung_transaktion  5   card4students.transaktion.id    1   Using where; Not exists
2   DERIVED filiale eq_ref  PRIMARY PRIMARY 4   card4students.transaktion.fk_filiale    1   
3   UNION   buchung ref konto   konto   1       337602  Using where
3   UNION   transaktion eq_ref  PRIMARY PRIMARY 4   card4students.buchung.fk_transaktion    1   
3   UNION   filiale eq_ref  PRIMARY PRIMARY 4   card4students.transaktion.fk_filiale    1   
3   UNION   auszahlung  eq_ref  PRIMARY PRIMARY 4   card4students.buchung.fk_auszahlung 1   
NULL    UNION RESULT    <union2,3>  ALL NULL    NULL    NULL    NULL    NULL    

要优化此查询,您只需要一个复合索引:

create index idx_transaktion_buchung on
    transaktion_buchung(fk_kunde, konto, stonriert, freigegeben_am, buchungstyp, betrag_eur);

这是查询的覆盖索引,因此应该非常快。

要优化此查询,您只需要一个复合索引:

create index idx_transaktion_buchung on
    transaktion_buchung(fk_kunde, konto, stonriert, freigegeben_am, buchungstyp, betrag_eur);

这是一个用于查询的覆盖索引,因此应该非常快。

我怀疑MySQL没有很好地使用任何索引。它可能返回一个非常大的结果集(使用联接的索引),但随后扫描每个返回的行以检查在WHERE子句中查找的值

因此,可能值得尝试在不使用视图的情况下编写查询。我想是这样的:-

SELECT  transaktion.fk_kunde AS fk_kunde, 
    transaktion.id AS fk_transaktion,  
    buchung.id AS fk_buchung, 
    NULL AS auszahlung_gewuenscht,  
    transaktion.betrag_eur AS betrag_eur, 
    transaktion.nettoumsatz AS nettoumsatz,  
    transaktion.mwst AS mwst, 
    NULL AS fk_abrechnung,  
    filiale.name AS filiale_name,  
    transaktion.storniert_am AS storniert_am, 
    transaktion.freigegeben_am AS freigegeben_am,  
    buchung.buchungstyp AS buchungstyp,  
    transaktion.konto AS konto, 
    0 AS auszahlung_vorgenommen, 
    transaktion.recordbirthdate AS recordbirthdate 
FROM transaktion 
LEFT JOIN buchung ON buchung.fk_transaktion = transaktion.id
LEFT JOIN filiale ON filiale.id = transaktion.fk_filiale
WHERE ISNULL(buchung.id) 
AND transaktion.fk_kunde=303276 
AND transaktion.konto='Cashback' 
AND transaktion.storniert_am IS NULL 
AND transaktion.freigegeben_am IS NULL  
AND (transaktion.buchungstyp!='Zahlung' 
OR transaktion.buchungstyp IS NULL)
UNION ALL 
SELECT  buchung.fk_kunde AS fk_kunde,  
    buchung.fk_transaktion AS fk_transaktion, 
    buchung.id AS fk_buchung,  
    buchung.auszahlung_gewuenscht AS auszahlung_gewuenscht, 
    buchung.betrag_eur AS betrag_eur,  
    transaktion.nettoumsatz AS nettoumsatz, 
    transaktion.mwst AS mwst,  
    auszahlung.fk_abrechnung AS fk_abrechnung,  
    filiale.name AS filiale_name,  
    transaktion.storniert_am AS storniert_am, 
    IF(ISNULL(transaktion.id), NOW(),  transaktion.freigegeben_am) AS freigegeben_am, 
    buchung.buchungstyp AS buchungstyp,  
    buchung.konto AS konto, 
    buchung.auszahlung_vorgenommen AS auszahlung_vorgenommen, 
    IF((transaktion.recordbirthdate IS NOT NULL),  
    transaktion.recordbirthdate, buchung.recordbirthdate) AS recordbirthdate 
FROM buchung 
LEFT JOIN transaktion ON transaktion.id = buchung.fk_transaktion 
LEFT JOIN filiale ON filiale.id = transaktion.fk_filiale
LEFT JOIN auszahlung ON auszahlung.id = buchung.fk_auszahlung
WHERE buchung.konto = _UTF8'Cashback'
AND buchung.fk_kunde=303276 
AND transaktion.storniert_am IS NULL 
AND transaktion.freigegeben_am IS NULL  
AND transaktion.id IS NOT NULL 
AND transaktion.freigegeben_am IS NULL
AND (buchung.buchungstyp!='Zahlung' 
OR buchung.buchungstyp IS NULL)

你可能需要一个涵盖fk_kunde和konto的buchung复合索引。在transaktion上,一个包含fk_kunde和konto的复合索引。

我怀疑MySQL没有很好地使用任何索引。它可能返回一个非常大的结果集(使用联接的索引),但随后扫描每个返回的行以检查在WHERE子句中查找的值

因此,可能值得尝试在不使用视图的情况下编写查询。我想是这样的:-

SELECT  transaktion.fk_kunde AS fk_kunde, 
    transaktion.id AS fk_transaktion,  
    buchung.id AS fk_buchung, 
    NULL AS auszahlung_gewuenscht,  
    transaktion.betrag_eur AS betrag_eur, 
    transaktion.nettoumsatz AS nettoumsatz,  
    transaktion.mwst AS mwst, 
    NULL AS fk_abrechnung,  
    filiale.name AS filiale_name,  
    transaktion.storniert_am AS storniert_am, 
    transaktion.freigegeben_am AS freigegeben_am,  
    buchung.buchungstyp AS buchungstyp,  
    transaktion.konto AS konto, 
    0 AS auszahlung_vorgenommen, 
    transaktion.recordbirthdate AS recordbirthdate 
FROM transaktion 
LEFT JOIN buchung ON buchung.fk_transaktion = transaktion.id
LEFT JOIN filiale ON filiale.id = transaktion.fk_filiale
WHERE ISNULL(buchung.id) 
AND transaktion.fk_kunde=303276 
AND transaktion.konto='Cashback' 
AND transaktion.storniert_am IS NULL 
AND transaktion.freigegeben_am IS NULL  
AND (transaktion.buchungstyp!='Zahlung' 
OR transaktion.buchungstyp IS NULL)
UNION ALL 
SELECT  buchung.fk_kunde AS fk_kunde,  
    buchung.fk_transaktion AS fk_transaktion, 
    buchung.id AS fk_buchung,  
    buchung.auszahlung_gewuenscht AS auszahlung_gewuenscht, 
    buchung.betrag_eur AS betrag_eur,  
    transaktion.nettoumsatz AS nettoumsatz, 
    transaktion.mwst AS mwst,  
    auszahlung.fk_abrechnung AS fk_abrechnung,  
    filiale.name AS filiale_name,  
    transaktion.storniert_am AS storniert_am, 
    IF(ISNULL(transaktion.id), NOW(),  transaktion.freigegeben_am) AS freigegeben_am, 
    buchung.buchungstyp AS buchungstyp,  
    buchung.konto AS konto, 
    buchung.auszahlung_vorgenommen AS auszahlung_vorgenommen, 
    IF((transaktion.recordbirthdate IS NOT NULL),  
    transaktion.recordbirthdate, buchung.recordbirthdate) AS recordbirthdate 
FROM buchung 
LEFT JOIN transaktion ON transaktion.id = buchung.fk_transaktion 
LEFT JOIN filiale ON filiale.id = transaktion.fk_filiale
LEFT JOIN auszahlung ON auszahlung.id = buchung.fk_auszahlung
WHERE buchung.konto = _UTF8'Cashback'
AND buchung.fk_kunde=303276 
AND transaktion.storniert_am IS NULL 
AND transaktion.freigegeben_am IS NULL  
AND transaktion.id IS NOT NULL 
AND transaktion.freigegeben_am IS NULL
AND (buchung.buchungstyp!='Zahlung' 
OR buchung.buchungstyp IS NULL)

你可能需要一个涵盖fk_kunde和konto的buchung复合索引。在transaktion上,一个包含fk_kunde和konto的复合索引。

1)购买更大的框2)将索引添加到
transaktion_buchung
表发布您的
transaktion_buchung
方案是否有人向您索要
EXPLAIN
?这是同一查询的解释吗?MySQL在使用视图方面非常差。它只是将它们视为子查询,而不使用索引来缩小结果范围。您最好选择用于视图的SELECT并直接使用它(使用上面SELECT中的where子句).1)购买更大的框2)向
transaktion\u buchung
表添加索引发布您的
transaktion\u buchung
方案是否有人向您索要
EXPLAIN
?这是对同一查询的解释吗?MySQL在使用视图方面非常差。它只是将它们视为子查询,而不使用索引来缩小结果范围。您最好选择用于视图的SELECT并直接使用它(使用上述SELECT中的where子句)。是否需要将
betrag\u eur
放入索引中?
stonriert
应该是
stonriert\u am
?transaktion\u buchung是一个视图。我已经在问题细节中添加了相关的模式是否有必要将
betrag\u eur
放入索引中?
stonriert
应该是
stonriert\u am
?transaktion\u buchung是一个视图。我已经在问题细节中添加了相关的模式