Mysql 左外联接长时间执行

Mysql 左外联接长时间执行,mysql,sql,Mysql,Sql,这是我的mysql查询: SELECT SUBSTR(`GuestDailyRate`, 3, 8) as price, a.duration as nights, SUBSTR(b.DebtorEffect, 3 , 8) as debtor FROM `ARR_2013` a OUTER LEFT JOIN `CMDextras` b ON a.`GuestCode` = b.`GuestCode` WHERE a.`GuestCode`=b.`GuestCode` AND b.Debto

这是我的mysql查询:

SELECT SUBSTR(`GuestDailyRate`, 3, 8) as price, a.duration as nights, SUBSTR(b.DebtorEffect, 3 , 8) as debtor
FROM `ARR_2013` a OUTER LEFT JOIN `CMDextras` b 
ON a.`GuestCode` = b.`GuestCode`
WHERE a.`GuestCode`=b.`GuestCode` AND b.DebtorEffect NOT LIKE '%(%' AND a.`GuestRateCategory` = 'BestAvaila' AND
YEAR(STR_TO_DATE(a.`ArrivalDate`,'%d-%M-%YY'))=2013 
花大约5分钟来显示结果


可以帮助我解决这个问题。

缺少模式和数量级行计数,因此我只能给出一些一般性提示:

  • 确保您在ARR_2013.GuestCode和CMDextras.GuestCode上有索引。你不是在用外键吗

  • 您是否每月使用单独的表格?如果您这样做,此架构将失去控制

  • WHERE子句(a.
    GuestCode
    =b.
    GuestCode
    )已过时,它已包含在联接的ON子句中

  • 与“%”不同(“%):使用LIKE和%字符进行字符串扩展通常不是很快。精确字符串匹配查询的速度比“LIKE”查询快得多。WHERE正在删除包含“(”-->可能会标记那些具有特殊tinyint列LIKE的行,并在写入行时指定括号

  • STR_TO_DATE:为什么不使用datetime列,这是一种二进制格式,它的范围过滤速度更快


  • 您可以尝试下面的查询。但请确保应为联接字段编制索引

    SELECT 
    SUBSTR(`GuestDailyRate`, 3, 8) as price, 
    a.duration as nights, 
    SUBSTR(b.DebtorEffect, 3 , 8) as debtor 
    FROM `ARR_2013` a 
    JOIN `CMDextras` b 
    ON a.`GuestCode` = b.`GuestCode`
    WHERE a.`GuestRateCategory` = 'BestAvaila' AND 
    b.DebtorEffect NOT LIKE '%(%' AND 
    YEAR(STR_TO_DATE(a.`ArrivalDate`,'%d-%M-%YY'))='2013';
    
    您可以通过以下几点进一步优化:

  • ArrivalDate应该是日期时间,而不是字符串

  • 如果字段GuestrateCegory上的条件过滤了大量数据,那么您可以索引此字段以获得快速结果


  • 首先:您的查询不正确。您正在外部加入cmdextras记录,但随后在WHERE子句中删除了所有外部加入的记录。请将
    b.debtoreffect与“%”(”
    )不同,移动到ON子句以避免此情况

    select 
      substr(guestdailyrate, 3, 8) as price, 
      a.duration as nights, 
      substr(b.debtoreffect, 3 , 8) as debtor
    from arr_2013 a 
    outer left join cmdextras b on a.guestcode = b.guestcode 
                                and b.debtoreffect not like '%(%' 
    where a.guestratecategory = 'bestavaila' 
    and right(a.arrivaldate, 2) = '13';
    
    然后:在数据库中看到以字符串形式存储的日期总是很可怕的。如果它们是以日期形式存储的,您可以使用一个可能更快的BETWEEN子句,前提是arrivaldate上有一个索引,并且只有一小部分记录在2013年。(看到价格和其他数据被存储为子字符串也很可怕。我建议更改整个数据库设计。)

    唯一的平等标准是guestratecategory。如果只有一小部分行的值为“bestavaila”,则需要索引来使用快速索引查找,而不是完整的表扫描。(顺便说一句:我建议使用类别表,而不是存储字符串。)

    您可以通过guestcode进行连接。若要快速执行此连接,guestcode上至少应该有一个索引,位于CMDETRAS表中


    编辑:还有一个想法:您的表名为ARR\u2013,您正在检查其记录的到达日期是否为2013?见鬼了?

    当您需要第二个表中的特定值时,为什么要使用外部联接?使用外部联接的原因是在第二个表中获取具有空值的行嗯,没有匹配项,但您的
    b.deborteffect与'%(“
    test将删除所有这些行。由于您已经基于a.
    GuestCode
    =b.
    GuestCode
    连接了两个表。在where子句中再次使用与where a.
    GuestCode
    =b.
    GuestCode
    相同的内容没有任何效果。我认为MySQL在看到该测试时会自动将其转换为内部连接。Do您在
    b.GuestCode
    a.guestractecategory
    上有索引吗?
    解释了什么
    说了什么?如何索引b.GuestCode和a.guestractecategory?5。)因为我的到达日期使用字符串类型,我知道APR_2013.GuestCode和CMDExtras.GuestCode都是FK to?您可以使用不同的方式加入,以利用GuestCode FK->APR_2013 a a a内部连接st ON a.GuestCode=st。外部左连接CMDExtras b ON b.GuestCode=st。至于ArrivalDate:您的选择与插入/更新查询的比率是多少?在mo中在大多数情况下,SELECT查询命中的记录比INSERT或UPDATE多。我建议在将字段输入数据库时,而不是在SELECT中,将字符串解析为datetime。