я хочу оптимизировать MySQL запрос - PullRequest
0 голосов
/ 06 июня 2018

Пожалуйста, ребята, помогите мне оптимизировать запрос ниже

SELECT
        `dti`.`CompanyId`, 
        `dti`.`Samiti`, 
        `dti`.`toll_date`, 
        `dti`.`MajorFee`, 
        `dti`.`MinorFee`, 
        `dti`.`SawalFee`, 
        SUM(dti.Tmwt) as Tmwt, 
        SUM(dti.Localminor) as Localminor, 
        SUM(dti.Swt) as Swt, 
        SUM(dti.Twt) as Twt, 
        SUM(((dti.Tmwt * dti.MajorFee) + (dti.Localminor * dti.MinorFee) + (dti.Swt * dti.SawalFee))) as total_wages, 
        SUM((dti.Twt * dti.govt_charges)) as govt_deduction, 
        SUM((((dti.Tmwt * dti.MajorFee) + (dti.Localminor * dti.MinorFee) + (dti.Swt * dti.SawalFee)) - (dti.Twt * dti.govt_charges))) as net_amount, 

        (SELECT (SUM(ld.amount) + SUM(ld.advance_deduction)) 
          FROM psac_liability_deduction ld 
          WHERE ld.status = "Active" AND 
                ld.from_date >="2017-08-24" AND 
                ld.to_date <="2017-08-31" AND 
                ld.deducted_for = dti.CompanyId
        ) as group_liability_deduction, 

        (SELECT CONCAT(SUM(wi.GroupLiabilityDeduction), "|", SUM(wi.AdvanceWagesDeduction)) 
            FROM psac_wagesitem wi 
            WHERE   wi.status="Active" AND 
                    wi.from_date >= "2017-08-24" AND 
                    wi.to_date <= "2017-08-31" AND 
                    wi.MainGroup=dti.Samiti AND 
                    wi.FishermanId=dti.CompanyId
        ) as wages_deduction, 

        (SELECT CONCAT(SUM(cdp.product_liability), "|", SUM(cdp.wages_liability)) 
            FROM psac_cash_deposited_payment cdp 
            WHERE   cdp.status="Active" AND 
                    cdp.deposit_date >= "2017-08-24" AND 
                    cdp.deposit_date <= "2017-08-31" AND 
                    cdp.maingroup_id=dti.Samiti AND 
                    cdp.fisherman_id=dti.CompanyId
        ) as cash_deposited, 
        `fm`.`Name` as `fishername`, 
        `fm`.`Code` as `fishername_code`, 
        `fm`.`Bank`, 
        `fm`.`IfscCode`, 
        `fm`.`AccountNo`

    FROM `psac_dailytollinfo` `dti`
    LEFT JOIN `psac_fisherman` `fm` ON `fm`.`ID`=`dti`.`CompanyId`
    WHERE 
    `dti`.`status` = 'Active' AND
    `dti`.`toll_date` >= '2017-08-24' AND
    `dti`.`toll_date` <= '2017-08-31'
    GROUP BY `dti`.`toll_date`, `dti`.`CompanyId`
    ORDER BY `dti`.`toll_date` ASC

Пожалуйста, помогите мне оптимизировать этот запрос.Если я удаляю подзапросы, это будет отлично работать, но с подзапросами это займет слишком много времени.ниже приведены структуры таблиц

psac_dailytollinfo table

   CREATE TABLE `psac_dailytollinfo` (
      `ID` int(11) NOT NULL,
      `toll_date` date NOT NULL,
      `Point` int(11) NOT NULL,
      `group_type` int(11) NOT NULL,
      `Samiti` int(11) NOT NULL,
      `DailytollId` int(11) NOT NULL,
      `CompanyId` int(11) NOT NULL,
      `Name` varchar(250) NOT NULL,
      `govt_charges` float(15,2) NOT NULL,
      `MajorFee` float(15,2) NOT NULL,
      `MinorFee` float(15,2) NOT NULL,
      `SawalFee` float(15,2) NOT NULL,
      `Cqty` varchar(150) NOT NULL,
      `Cwt` varchar(150) NOT NULL,
      `Rqty` varchar(150) NOT NULL,
      `Rwt` varchar(150) NOT NULL,
      `Mqty` varchar(150) NOT NULL,
      `Mwt` varchar(150) NOT NULL,
      `Kqty` varchar(150) NOT NULL,
      `Kwt` varchar(150) NOT NULL,
      `Aqty` varchar(150) NOT NULL,
      `Awt` varchar(150) NOT NULL,
      `Sqty` varchar(11) NOT NULL,
      `Swt` varchar(11) NOT NULL,
      `Lqty` varchar(150) NOT NULL,
      `Lwt` varchar(150) NOT NULL,
      `Localminor` varchar(150) NOT NULL,
      `Tmqty` varchar(150) NOT NULL,
      `Tmwt` varchar(150) NOT NULL,
      `Tqty` varchar(150) NOT NULL,
      `Twt` varchar(150) NOT NULL,
      `added_by` int(11) NOT NULL,
      `updated_by` int(11) NOT NULL,
      `added_date` datetime NOT NULL,
      `updated_date` datetime NOT NULL,
      `action_microtime` varchar(20) NOT NULL,
      `status` enum('Active','Inactive','Deleted') NOT NULL DEFAULT 'Active'
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

psac_liability_deduction table

CREATE TABLE `psac_liability_deduction` (
  `ID` bigint(20) NOT NULL,
  `wages_id` int(11) NOT NULL,
  `wages_item_id` int(11) NOT NULL,
  `amount` float(15,2) NOT NULL,
  `advance_deduction` float(11,2) NOT NULL,
  `group_type_id` int(11) NOT NULL,
  `maingroup_id` int(11) NOT NULL,
  `deducted_by` int(11) NOT NULL,
  `deducted_for` int(11) NOT NULL,
  `from_date` date NOT NULL,
  `to_date` date NOT NULL,
  `status` enum('Active','Inactive','Deleted') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'Active',
  `added_by` int(11) NOT NULL,
  `updated_by` int(11) NOT NULL,
  `added_date` datetime NOT NULL,
  `updated_date` datetime NOT NULL,
  `action_microtime` varchar(50) COLLATE utf8_unicode_ci NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

psac_wagesitem table

 CREATE TABLE `psac_wagesitem` (
      `ID` int(11) NOT NULL,
      `wages_for` enum('Fisherman','Group') NOT NULL DEFAULT 'Fisherman',
      `wages_id` int(11) NOT NULL,
      `from_date` date NOT NULL,
      `to_date` date NOT NULL,
      `group_type_id` int(11) NOT NULL,
      `MainGroup` int(11) NOT NULL,
      `FishermanId` int(11) NOT NULL,
      `MajorFee` float(15,2) NOT NULL,
      `MinorFee` float(15,2) NOT NULL,
      `SawalFee` float(15,2) NOT NULL,
      `major_wt` float(15,2) NOT NULL,
      `minor_wt` float(15,2) NOT NULL,
      `sawal_wt` float(15,2) NOT NULL,
      `major_wage` float(15,2) NOT NULL,
      `minor_wage` float(15,2) NOT NULL,
      `sawal_wage` float(15,2) NOT NULL,
      `TotalWage` float(15,2) NOT NULL,
      `group_liability` float(15,2) NOT NULL,
      `advance_wages` float(15,2) NOT NULL,
      `GovDeduction` float(15,2) NOT NULL,
      `GroupLiabilityDeduction` float(15,2) NOT NULL,
      `AdvanceWagesDeduction` float(15,2) NOT NULL,
      `final_wages` float(15,2) NOT NULL,
      `added_by` int(11) NOT NULL,
      `updated_by` int(11) NOT NULL,
      `added_date` datetime NOT NULL,
      `updated_date` datetime NOT NULL,
      `action_microtime` varchar(20) NOT NULL,
      `status` enum('Active','Inactive','Deleted') NOT NULL DEFAULT 'Active',
      `editable` enum('Lock','Unlock') NOT NULL DEFAULT 'Unlock'
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1;

psac_cash_deposited_p Таблица выплат

CREATE TABLE `psac_cash_deposited_payment` (
  `deposit_id` int(11) NOT NULL,
  `deposited_by` enum('Fisherman','Group') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'Fisherman',
  `deposit_date` date NOT NULL,
  `group_type_id` int(11) NOT NULL,
  `maingroup_id` int(11) NOT NULL,
  `fisherman_id` int(11) NOT NULL,
  `product_liability` float(11,2) NOT NULL,
  `wages_liability` float(11,2) NOT NULL,
  `receipt_number` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `remark` text COLLATE utf8_unicode_ci NOT NULL,
  `status` enum('Active','Inactive','Deleted') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'Active',
  `editable` enum('Lock','Unlock') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'Unlock',
  `added_by` int(11) NOT NULL,
  `added_date` datetime NOT NULL,
  `updated_by` int(11) NOT NULL,
  `updated_date` datetime NOT NULL,
  `action_microtime` varchar(20) COLLATE utf8_unicode_ci NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

1 Ответ

0 голосов
/ 08 июня 2018
  • Вы понимаете, что смотрите на целых 8 дней?Если вам нужна только одна неделя, измените <= на <.
  • Переключите все таблицы на InnoDB.
  • У вас есть PRIMARY KEY для каждой таблицы - либо «естественный» PK(состоит из одного или нескольких столбцов, которые вместе однозначно определяют каждую строку) или AUTO_INCREMENT.
  • dti нужно INDEX(status, toll_date)
  • Не использовать (m,n) вFLOAT, это приводит к дополнительному округлению.
  • Не используйте FLOAT для денег, это приводит к округлению.
  • FLOAT (с или без (m,n))содержит не более 7 значащих цифр.
  • Рассмотрим DECIMAL(11,2) вместо float(11,2).
  • Будьте осторожны при использовании latin1 в одной таблице и utf8 в другой - если вам нужно JOIN на VARCHAR;он должен иметь ту же кодировку и сопоставление, чтобы использовать индекс.
  • Там, где это возможно, сделать ORDER BY идентичным GROUP BY.

Этим составным индексы, которые могут повысить производительность:

dti:  INDEX(status, toll_date)
ld:   INDEX(status, deducted_for, from_date)
ld:   INDEX(status, deducted_for, to_date)
wi:   INDEX(status, MainGroup, FishermanId, from_date)
wi:   INDEX(status, MainGroup, FishermanId, to_date)
cdp:  INDEX(status, maingroup_id, fisherman_id, deposit_date)

(Дата должна быть последней; остальные столбцы могут быть в любом порядке.)

Если у вас все еще естьпроблемы с производительностью для подзапросов после добавления этих индексов, давайте посмотрим EXPLAIN SELECT ..., чтобы мы могли посмотреть снова.

Не распределяйте массив по столбцам:

  `Cqty` varchar(150) NOT NULL,
  `Cwt` varchar(150) NOT NULL,
  etc

Рассмотрите возможность qty и wt как два столбца в другой таблице.

Может ли быть два разных значения для MajorFee в один день для одной компании?Это и другие вещи говорят, что GROUP BY сформирован неправильно.

...