如何提高mysql查询性能?

时间:2021-07-26 14:06:06

标签: mysql

我在rental_schedules 表中有大约400 万条记录和大约1k 前提,获取数据最多需要1.5 秒。现在是时候了,或者我可以以某种方式优化更多?这是我的查询:

select
  count(*) as aggregate
from
  `premises`
where
  exists (
    select
      *
    from
      `rental_schedules`
    where
      `premises`.`id` = `rental_schedules`.`premises_id`
      and `date` >= '2021-07-01'
      and `public_enterprise` = 0
      and `rental_schedule_status` = 1
  )
  and exists (
    select
      id
    from
      rental_schedules
    where
      premises.id = rental_schedules.premises_id
      and public = 1
      and public_enterprise = 0
  )

这是我的前提表索引:

  PRIMARY KEY (`id`),
  KEY `premises_institution_id_foreign` (`institution_id`),
  KEY `premises_responsible_user_id_foreign` (`responsible_user_id`),
  KEY `premises_cover_type_id_foreign` (`cover_type_id`),
  KEY `premises_premises_type_id_foreign` (`premises_type_id`),
  CONSTRAINT `premises_cover_type_id_foreign` FOREIGN KEY (`cover_type_id`) REFERENCES `cover_types` (`id`),
  CONSTRAINT `premises_institution_id_foreign` FOREIGN KEY (`institution_id`) REFERENCES `institutions` (`id`) ON DELETE CASCADE,
  CONSTRAINT `premises_premises_type_id_foreign` FOREIGN KEY (`premises_type_id`) REFERENCES `premises_types` (`id`),
  CONSTRAINT `premises_responsible_user_id_foreign` FOREIGN KEY (`responsible_user_id`) REFERENCES `dashboard_users` (`id`)

这是我的租赁时间表表索引:

  PRIMARY KEY (`id`),
  KEY `rental_schedules_date_index` (`date`),
  KEY `rental_schedules_week_day_id_foreign` (`week_day_id`),
  KEY `rental_schedules_rental_schedule_status_foreign` (`rental_schedule_status`),
  KEY `rental_schedules_contract_id_foreign` (`contract_id`),
  KEY `rental_schedules_bill_id_foreign` (`bill_id`),
  KEY `rental_schedules_accordion_id_index` (`accordion_id`),
  KEY `premises_search` (`premises_id`,`rental_schedule_status`,`date`,`public_enterprise`),
  KEY `rental_schedules_search` (`premises_id`,`public`,`public_enterprise`,`rental_schedule_status`),
  KEY `rental_schedules_search_with_date` (`premises_id`,`public`,`public_enterprise`,`rental_schedule_status`,`date`),
  CONSTRAINT `rental_schedules_bill_id_foreign` FOREIGN KEY (`bill_id`) REFERENCES `bills` (`id`) ON DELETE SET NULL,
  CONSTRAINT `rental_schedules_contract_id_foreign` FOREIGN KEY (`contract_id`) REFERENCES `contracts` (`id`) ON DELETE SET NULL,
  CONSTRAINT `rental_schedules_premises_id_foreign` FOREIGN KEY (`premises_id`) REFERENCES `premises` (`id`),
  CONSTRAINT `rental_schedules_rental_schedule_status_foreign` FOREIGN KEY (`rental_schedule_status`) REFERENCES `rental_schedule_statuses` (`id`),
  CONSTRAINT `rental_schedules_week_day_id_foreign` FOREIGN KEY (`week_day_id`) REFERENCES `week_days` (`id`)

提前感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

我可能忽略了它,但我认为这里不需要 2 个不同的 EXISTS 运算符。因此您的查询可以优化为 -

select count(*) as aggregate
  from `premises`
 where exists (select null
                 from `rental_schedules`
                where `premises`.`id` = `rental_schedules`.`premises_id`
                  and `date` >= '2021-07-01'
                  and `public_enterprise` = 0
                  and `rental_schedule_status` = 1
                  and public = 1);

答案 1 :(得分:1)

SELECT COUNT(*) AS aggregate
    FROM premises AS p
    JOIN rental_schedules AS rs  ON p.`id` = rs.`premises_id`
    WHERE `date` >= '2021-07-01'
      AND `public_enterprise` = 0
      AND `rental_schedule_status` = 1
      AND public = 1;

rental_schedules 上的这个“复合”和“覆盖”索引会有所帮助:

INDEX(public_enterprise, rental_schedule_status, public, date, premises_id)

列的顺序很重要——首先是 =,然后是范围 >=,最后是“覆盖”所需的任何其他内容。

如果所有这些 id 都是 BIGINT,请注意每个 id 占用 8 个字节,并且大小可能有点过大。