Запрос Mysql с 2 внутренними объединениями и включающей оптимизацию выбора - PullRequest
0 голосов
/ 21 октября 2019

У меня есть этот запрос MySQL, который я запускаю каждые две минуты, и я делаю это 4 раза в parralel, что означает, что каждые две минуты этот запрос выполняется 4 раза (с разными значениями в параметрах), и через некоторое время моя база данныхперегружен, я пытался сделать кучу обновлений, чтобы оптимизировать его, чем больше могу, но мои знания SQL заканчиваются, поэтому я обращаюсь к вам, что я могу сделать, чтобы оптимизировать этот запрос?

SELECT bill.* FROM billing bill
   INNER JOIN subscriber s ON (s.subscriber_id = bill.subscriber_id)  
   INNER JOIN subscription sub ON(s.subscriber_id = sub.subscriber_id)          
   WHERE s.status = 'C' 
   AND bill.subscription_id = sub.subscription_id                       
   AND sub.package_name = 598
   AND sub.renewable = 1
   AND bill.billing_value IN ('not_ok BILLTOBE','not_ok BILL010 2','not_ok BILL010','not_ok BILL010 3')             
   AND sub.store = 'MTargetStore'
   AND (
     SELECT bill2.billing_date
     FROM billing bill2
     WHERE bill2.subscriber_id = bill.subscriber_id
     AND bill2.subscription_id = bill.subscription_id 
     AND bill2.billing_value NOT IN('not_ok BILL010','not_ok BILL010 2','not_ok BILL010 3')
     ORDER BY bill2.billing_date DESC LIMIT 1
   ) = bill.billing_date LIMIT 300

Показать таблицу создания для подписчика и биллинга (без лишних параметров)

Подписка

CREATE TABLE `subscription` (
      `subscription_id` int(11) NOT NULL AUTO_INCREMENT,
      `subscriber_id` int(11) NOT NULL,
      `renewable` tinyint(1) DEFAULT '0',
      `store` varchar(127) DEFAULT 'GooglePlay',

   `package_name` text,
PRIMARY KEY (`subscription_id`),
KEY `subscription_subscriber_id_subscriber_subscriber_id_idx` (`subscriber_id`),
KEY `renewableindex` (`renewable`),
KEY `subscription_index1` (`renewable`,`subscriber_id`,`subscription_id`),
KEY `subscription_index2` (`renewable`,`subscription_id`,`subscriber_id`),
CONSTRAINT `subscription_subscriber_id_subscriber_subscriber_id`
      FOREIGN KEY (`subscriber_id`)
      REFERENCES `subscriber` (`subscriber_id`)
      ON DELETE CASCADE ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=2282403 DEFAULT CHARSET=utf8

Подписчик

CREATE TABLE `subscriber` (
   `udid` varchar(100) NOT NULL,
   `subscriber_id` int(11) NOT NULL AUTO_INCREMENT,
   `status` varchar(3) DEFAULT 'CE',
   `consumer_id` varchar(250) DEFAULT NULL,
   PRIMARY KEY (`subscriber_id`),
   UNIQUE KEY `udid_UNIQUE` (`udid`),
   UNIQUE KEY `subscriber_os_email_key` (`email`,`os`),
   UNIQUE KEY `consumer_id_UNIQUE` (`consumer_id`),
   KEY `sub_id_status` (`status`,`subscriber_id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=3655055 DEFAULT CHARSET=utf8

Биллинг

CREATE TABLE `billing` (
   `billing_id` int(11) NOT NULL AUTO_INCREMENT,
   `billing_date` timestamp NULL DEFAULT NULL,
   `subscriber_id` int(11) NOT NULL,
   `billing_value` varchar(40) DEFAULT NULL,
   `subscription_id` int(11) DEFAULT NULL,
   PRIMARY KEY (`billing_id`),
   KEY `billing_subscriber_id_subscriber_subscriber_id_idx` (`subscriber_id`),
   KEY `subscriptionid` (`subscription_id`),
   CONSTRAINT `billing_subscriber_id_subscriber_subscriber_id`
         FOREIGN KEY (`subscriber_id`) REFERENCES `subscriber` (`subscriber_id`)
         ON DELETE NO ACTION ON UPDATE NO ACTION
 ) ENGINE=InnoDB AUTO_INCREMENT=9013743 DEFAULT CHARSET=utf8
* 1014И, наконец, объяснение первоначального запроса:
1   PRIMARY sub ref PRIMARY,subscription_subscriber_id_subscriber_subscriber_id_idx,renewableindex,subscription_index1,subscription_index2  renewableindex  2   const   171836  Using where
1   PRIMARY s   eq_ref  PRIMARY,sub_id_status   PRIMARY 4   Infinitgame.sub.subscriber_id   1   Using where
1   PRIMARY bill    ref billing_subscriber_id_subscriber_subscriber_id_idx,subscriptionid   billing_subscriber_id_subscriber_subscriber_id_idx  4   Infinitgame.sub.subscriber_id   14  Using where
2   DEPENDENT SUBQUERY  bill2   ref billing_subscriber_id_subscriber_subscriber_id_idx,subscriptionid   billing_subscriber_id_subscriber_subscriber_id_idx  4   Infinitgame.bill.subscriber_id  14  Using where; Using filesort

(или)

1   PRIMARY sub  ref             --  renewableindex  2  const                       171836  Using where
1   PRIMARY s    eq_ref          --  PRIMARY         4  Infinitgame.sub.subscriber_id    1  Using where
1   PRIMARY bill ref             --  bsss            4  Infinitgame.sub.subscriber_id   14  Using where
2   DEPENDENT SUBQUERY bill2 ref --  bsss            4  Infinitgame.bill.subscriber_id  14  Using where; Using filesort

1 Ответ

1 голос
/ 21 октября 2019

Вместо

        SELECT  bill2.billing_date
            FROM  billing bill2
            WHERE ...
            ORDER BY  bill2.billing_date DESC
            LIMIT  1 

Скажите

        SELECT  MAX(bill2.billing_date)
            FROM  billing bill2
            WHERE ...

Вам действительно нужно 300 строк? Я подозреваю, что это приводит к 300 оценкам этого подзапроса.

    INNER JOIN subscriber s    ON (s.subscriber_id = bill.subscriber_id)  
    INNER JOIN subscription sub ON(s.subscriber_id =  sub.subscriber_id)          
    WHERE  s.status = 'C'
      AND  bill.subscription_id IN ( ... )
      AND  bill.subscription_id = sub.subscription_id
      AND  sub.package_name = 598
      AND  sub.renewable = 1
      AND  sub.store = 'MTargetStore'

Имеют эти индексы (неясно, какой из них будет наиболее полезным):

s:  INDEX(status, subscriber_id)    -- (indexing flags is rarely useful)
bill:  INDEX(subscription_id)
sub:  INDEX(package_name, store, renewable, subscriber_id, subscription_id)
sub:  INDEX(package_name, store, renewable, subscription_id, subscriber_id)

Два индекса для sub - зависит от того, в каком порядке оптимизатор решит получить доступ к таблицам.

AND  bill.subscription_id = sub.subscription_id

Разве это не должно быть частью ON? Кажется, он определяет отношение.

A LIMIT без и ORDER BY - вы получите непредсказуемый набор строк;Это нормально?

Чтобы обсудить это подробнее, укажите SHOW CREATE TABLE для каждой таблицы и EXPLAIN SELECT ....

Кроме того, каково значение

 SELECT COUNT(DISTINCT subscriber_id, subscription_id)
     FROM  billing
     WHERE billing_value NOT IN('not_ok BILL010','not_ok BILL010 2',
                                'not_ok BILL010 3')

Ответ может привести к другому способу выполнения подзапроса.

Кроме того, это сработало бы так же, как и NOT IN?

     WHERE billing_value NOT LIKE 'not_ok BILL010%'

При сравнении строки (или TEXT) в числовую строку, заключите строку в кавычки:

  AND sub.package_name = "598"

Без кавычек индекс, использующий package_name, не может быть эффективно использован.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...