Mysql

如何在不損失性能的情況下將表分成兩部分?

  • February 2, 2020

根據https://stackoverflow.com/a/174047/14731,拆分不常用的列可以釋放記憶體,從而可以更快地檢索常用列。

我有一個表,其列總是一起檢索,但出於設計原因,我仍然想將它們拆分(減少跨多個表的重複,提高程式碼重用)。例如,我有不同的表使用相同的權限方案。我不想向每個表添加權限列,而是使用外鍵來引用單獨的權限方案表。

我用 100 萬行填充 MySQL,對兩個版本執行查詢,發現帶有 JOIN 的版本慢了約 3 倍(0.9 秒對 2.9 秒)。

這是我的表:

original
(
   id BIGINT NOT NULL,
   first BIGINT NOT NULL,
   second BIGINT NOT NULL,
   third BIGINT NOT NULL
);
part1
(
   id BIGINT NOT NULL,
   first BIGINT NOT NULL,
   second BIGINT NOT NULL,
   PRIMARY KEY(id)
);
part2
(
   link BIGINT NOT NULL,
   third BIGINT NOT NULL,
   FOREIGN KEY (link) REFERENCES part1(id)
);

這是我的查詢:

SELECT first, second, third FROM original;
SELECT part1.first, part1.second, part2.third FROM part1, part2 WHERE part2.link = part1.id;

有什麼辦法可以降低拆分設計的性能成本?


如果您想在您身邊重現此測試,您可以使用以下 Java 應用程序生成 SQL 腳本來填充數據庫:

import java.io.FileNotFoundException;
import java.io.PrintWriter;

public class Main
{
   public static void main(String[] args) throws FileNotFoundException
   {
       final int COUNT = 1_000_000;
       try (PrintWriter out = new PrintWriter("/import.sql"))
       {
           for (int i = 0; i < COUNT; ++i)
               out.println("INSERT INTO original VALUES (" + i + ", " + i + ", 0);");
           out.println("INSERT INTO original VALUES (" + (COUNT - 2) + ", " + (COUNT - 1) +
               ", 1);");
           out.println();
           for (int i = 0; i < COUNT; ++i)
           {
               out.println("INSERT INTO part1 (first, second) VALUES (" + i + ", " + i + ");");
               out.println("INSERT INTO part2 VALUES (LAST_INSERT_ID(), 0);");
           }
           out.println("INSERT INTO part1 (first, second) VALUES (" + (COUNT - 2) + ", " +
               (COUNT - 1) + ");");
           out.println("INSERT INTO part2 VALUES (LAST_INSERT_ID(), 1);");
           out.println();
       }
   }
}

這正是在有限範圍內使用正規化並在性能測試之後的原因。規範化是以連接(排序)為代價的。5NF 上 DWH 的主要目的是安全地儲存數據,而不是快速檢索數據。

備選方案 1 有一個物化視圖的概念:保存在硬碟驅動器上的視圖。MySQL 沒有提供開箱即用的功能,但這篇文章 - MySQL 的物化視圖- 解釋瞭如何通過 SP 更新/刷新表來重新創建此功能。

物化視圖 (MV) 是查詢的預計算(物化)結果。與簡單的 VIEW 不同,物化視圖的結果儲存在某處,通常在表中。當需要立即響應並且物化視圖所基於的查詢需要很長時間才能產生結果時,使用物化視圖。物化視圖必須不時刷新。這取決於物化視圖的刷新頻率及其內容的實際程度。基本上,物化視圖可以立即或延遲刷新,它可以完全刷新或到某個時間點。MySQL 本身不提供物化視圖。

備選方案 2 您可以嘗試通過其他方式來實現您的設計。與其拆分主表,不如從主表創建 2-3 個視圖或表。這樣,您將擁有具有不同值的星型模式的標準化表,並且您將保留主快速表。

性能調整總是關於 CPU(時間)、RAM 和 IO(吞吐量或空間)之間的權衡。在這種情況下,它位於 CPU 和 IO 之間。

引用自:https://dba.stackexchange.com/questions/74693