簡體   English   中英

MySQL 為兩個具有相同索引的大表優化性能

[英]MySQL optimized performance for two large tables with same index

我有兩張表,其中包含大量數據(主表約 180 萬,輔助表約 120 萬),如下所示:

訂閱者表(id,名稱,email,國家,account_status,...)subscriber_payment_table(id,subscriber_id,payment_type,payment_credential)

我的最終目標是有一個表,包含所有用戶及其支付表(如果不存在,則為 null),直到昨天,並且 account_status = 1(活動)

大多數訂閱者都有相應的訂閱者付款,因此使用 INNER JOIN 不是一個可行的選擇,並且使用 LEFT JOIN 讓我最終得到 SQL 在經過大量處理工作后 2 小時后我的查詢超時。

SELECT 
    `subscribers`.`id` AS `id`,
    `subscribers`.`email` AS `email`,
    `subscribers`.`name` AS `name`,
    `subscribers`.`geoloc_country` AS `country`,

    `subscribers_payment`.`payment_type` AS `paymentType`,
    `subscribers_payment`.`payment_credential` AS `paymentCredential`

    `subscribers`.`create_datetime` AS `createdAt`
FROM
    `subscribers`
LEFT JOIN 
    `subscribers_payment` ON (`subscribers_payment`.`subscriberId` = `subscribers`.`id`)
WHERE
    `subscribers`.`account_status` = 1
    AND DATE_FORMAT(CAST(`subscribers`.`create_datetime` AS DATE), '%Y-%m-%d') < curdate())

如前所述,此查詢花費了太多時間,最終超時且無法正常工作。 我還考慮在“所有訂閱者”和“付費訂閱者”之間建立一個 UNION。

(
SELECT 
    `subscribers`.`id` AS `id`,
    `subscribers`.`email` AS `email`,
    `subscribers`.`name` AS `name`,
    `subscribers`.`geoloc_country` AS `country`,

    null AS `paymentType`,
    null AS `paymentCredential`

    `subscribers`.`create_datetime` AS `createdAt`
FROM
    `subscribers`
WHERE
    `subscribers`.`account_status` = 1
    AND DATE_FORMAT(CAST(`subscribers`.`create_datetime` AS DATE), '%Y-%m-%d') < curdate()))
UNION
(
SELECT 
    `subscribers`.`id` AS `id`,
    `subscribers`.`email` AS `email`,
    `subscribers`.`name` AS `name`,
    `subscribers`.`geoloc_country` AS `country`,

    `subscribers_payment`.`payment_type` AS `paymentType`,
    `subscribers_payment`.`payment_credential` AS `paymentCredential`

    `subscribers`.`create_datetime` AS `createdAt`
FROM
    `subscribers`
INNERJOIN 
    `subscribers_payment` ON (`subscribers_payment`.`subscriberId` = `subscribers`.`id`)
WHERE
    `subscribers`.`account_status` = 1
    AND DATE_FORMAT(CAST(`subscribers`.`create_datetime` AS DATE), '%Y-%m-%d') < curdate()))

當前實現的問題是我得到了重復的查詢(我正在使用 UNION 但它沒有將我的結果組合在一起並刪除非不同的值,這是因為我在paymentTypepaymentCredential列中有不同的值)

這個查詢運行大約 2 分鍾,所以這對我來說更可行。 我只需要消除重復記錄.. 除非這里有更明智的選擇

免責聲明:我們使用的是 MyISAM 表,因此使用外鍵來加速查詢是不行的。

對於此查詢:

SELECT  . . . 
FROM subscribers s LEFT JOIN
     subscribers_payment sp
     ON sp.subscriberId = s.id
WHERE s.account_status = 1 AND
      s.create_datetime < curdate();

然后,您需要一個關於subscribers(account_status, create_datetime, id)subscribers_payment(subscriberId)的索引。

我猜測subscriber_payment上的索引丟失了,這解釋了性能問題。

筆記:

  • 使用表別名——它們使查詢更易於編寫和閱讀。
  • 出於比較目的,不需要將datetime時間轉換為字符串。
  • 不需要對所有標識符使用反引號。 它們只是使查詢更難編寫和閱讀。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM