MySQL视图查询需要很长时间才能加载

时间:2016-12-15 16:24:07

标签: mysql sql

我在MySQL中创建了一个视图

CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` 
SQL SECURITY DEFINER VIEW `inventory_view` AS 
select (case when isnull(`a`.`items_sold`) then 0 else `a`.`items_sold` end) AS `sold_qty`,
       (case when isnull(`a`.`items_bought`) then 0 else `a`.`items_bought` end) AS `bought_qty`,
       (case when isnull(`a`.`credit`) then 0 else `a`.`credit` end) AS `credit_amount`,
       (case when isnull(`a`.`debit`) then 0 else `a`.`debit` end) AS `debit_amount`,
       (case when isnull(`tv`.`count`) then 0 else `tv`.`count` end) AS `tranfers`,
       (case when isnull(`a`.`inhand`) then 0 else `a`.`inhand` end) AS `balance`,
       (case when isnull(`tv`.`count`) then `a`.`inhand` when isnull(`a`.`inhand`) then `tv`.`count` else (`a`.`inhand` + `tv`.`count`) end) AS `in_hand`,
       (case when isnull(`a`.`company_id`) then `tv`.`fk_company` else `a`.`company_id` end) AS `company`,
       (case when isnull(`a`.`branch_id`) then `tv`.`fk_branch` else `a`.`branch_id` end) AS `branch`,
       (case when isnull(`a`.`item_code`) then convert(`tv`.`fk_item_code` using utf8) else convert(`a`.`item_code` using utf8) end) AS `item`,
       (case when isnull(`a`.`operator`) then `tv`.`user` else `a`.`operator` end) AS `fk_operator` 
from (`transfer_view` `tv` left join `inventory_main` `a` on(((convert(`tv`.`fk_item_code` using utf8) = convert(`a`.`item_code` using utf8)) and (`a`.`operator` = `tv`.`user`))))
union 
select (case when isnull(`a`.`items_sold`) then 0 else `a`.`items_sold` end) AS `sold_qty`,
       (case when isnull(`a`.`items_bought`) then 0 else `a`.`items_bought` end) AS `bought_qty`,
       (case when isnull(`a`.`credit`) then 0 else `a`.`credit` end) AS `credit_amount`,
       (case when isnull(`a`.`debit`) then 0 else `a`.`debit` end) AS `debit_amount`,
       (case when isnull(`tv`.`count`) then 0 else `tv`.`count` end) AS `tranfers`,
       (case when isnull(`a`.`inhand`) then 0 else `a`.`inhand` end) AS `balance`,
       (case when isnull(`tv`.`count`) then `a`.`inhand` when isnull(`a`.`inhand`) then `tv`.`count` else (`a`.`inhand` + `tv`.`count`) end) AS `in_hand`,
       (case when isnull(`a`.`company_id`) then `tv`.`fk_company` else `a`.`company_id` end) AS `company`,
       (case when isnull(`a`.`branch_id`) then `tv`.`fk_branch` else `a`.`branch_id` end) AS `branch`,
       (case when isnull(`a`.`item_code`) then convert(`tv`.`fk_item_code` using utf8) else convert(`a`.`item_code` using utf8) end) AS `item`,
       (case when isnull(`a`.`operator`) then `tv`.`user` else `a`.`operator` end) AS `fk_operator` 
from (`inventory_main` `a` left join `transfer_view` `tv` on(((convert(`tv`.`fk_item_code` using utf8) = convert(`a`.`item_code` using utf8)) and (`a`.`operator` = `tv`.`user`))));

它有数千条记录并且执行速度非常慢。我运行的任何查询大约需要50秒。

您能否帮我找出错误或建议更好的方法来创建视图?

1 个答案:

答案 0 :(得分:0)

在transfer_view的fk_item_code和user上创建一个复合索引。

在inventory_main的item_code和operator上创建一个复合索引。

尝试将您的部分语句切换为使用coalesce,如下所示:

create view inventory_view as

select 
       coalesce(a.items_sold, 0) as sold_qty,
       coalesce(a.items_bought, 0) as bought_qty,
       coalesce(a.credit, 0) as credit_amount,
       coalesce(a.debit, 0) as debit_amount,
       coalesce(tv.count, 0) as transfers,
       coalesce(a.inhand, 0) as balance,
       coalesce(tv.count, 0) + coalesce(a.inhand, 0) as in_hand,
       coalesce(a.company_id, tv.fk_company) as company,
       coalesce(a.branch_id, tv.fk_branch) as branch,
       convert(coalesce(a.item_code, tv.fk_item_code) using utf8) as item,
       coalesce(a.operator, tv.user) as fk_operator
from transfer_view tv
left join inventory_main a
       on convert(tv.fk_item_code using utf8) = convert(a.item_code using utf8) 
       and a.operator = tv.user

union 

select 
       coalesce(a.items_sold, 0) as sold_qty,
       coalesce(a.items_bought, 0) as bought_qty,
       coalesce(a.credit, 0) as credit_amount,
       coalesce(a.debit, 0) as debit_amount,
       coalesce(tv.count, 0) as transfers,
       coalesce(a.inhand, 0) as balance,
       coalesce(tv.count, 0) + coalesce(a.inhand, 0) as in_hand,
       coalesce(a.company_id, tv.fk_company) as company,
       coalesce(a.branch_id, tv.fk_branch) as branch,
       convert(coalesce(a.item_code, tv.fk_item_code) using utf8) as item,
       coalesce(a.operator, tv.user) as fk_operator
from inventory_main a
left join transfer_view tv 
       on convert(tv.fk_item_code using utf8) = convert(a.item_code using utf8)
       and a.operator = tv.user;

这会改善查询的效果吗?

如果没有,以下是我推荐的步骤:

  • 查找两个表之间的匹配记录
  • 查找transfer_view中的所有记录,并且在inventory_main
  • 中没有匹配的记录
  • 查找inventory_main中的所有记录,其中transfer_view
  • 中没有匹配的记录
  • union all三个数据集

示例 -

create view inventory_view as

select 
    ...
from transfer_view tv
inner join inventory_main a
    on tv.fk_item_code = a.item_code -- you can convert ONLY if you need
    and a.operator = tv.user

union all

select
    ...
from transfer_view tv
where not exists (
    select 1 from inventory_main
    where item_code = tv.fk_item_code and operator = tv.user
)

union all

select
    ...
from inventory_main a
where not exists (
    select 1 from transfer_view
    where fk_item_code = a.item_code and user = a.operator
);