簡體   English   中英

MySQL 性能:多表與單表和分區上的索引

[英]MySQL performance: multiple tables vs. index on single table and partitions

我想知道什么在性能上更高效、更快:
在一個大表或多個沒有索引的小表上有一個索引?

由於這是一個非常抽象的問題,讓我讓它更實用:
我有一張關於用戶統計信息的表(20,000 個用戶和大約 3000 萬行)。 該表有大約 10 列,包括user_idactionstimestamps等。
最常見的應用是: 按user_id插入數據並按user_id檢索數據( SELECT語句從不包含多個user_id's )。

現在到目前為止,我在user_id上有一個INDEX ,查詢看起來像這樣

SELECT * FROM statistics WHERE user_id = 1

現在,隨着行越來越多,表格變得越來越慢。 INSERT語句變慢,因為INDEX越來越大; SELECT語句會變慢,因為要搜索的行數更多。

現在我想知道為什么不為每個用戶有一個統計表,而是將查詢語法更改為這樣的:

SELECT * FROM statistics_1

其中1顯然代表user_id
這樣,不需要INDEX並且每個表中的數據少得多,因此INSERTSELECT語句應該快得多。

現在我的問題再次:
處理如此多的表(在我的情況下為 20,000)而不是使用一個帶有INDEX表是否有任何現實世界的缺點?
我的方法是否真的會加快速度,或者表格的查找最終會比一切都減慢速度嗎?

創建 20,000 個表是個壞主意。 不久您將需要 40,000 張桌子,然后更多。

我在我的書SQL Antipatterns中將這種綜合症稱為元數據 Tribbles 每次您計划創建“每個 X 的表”或“每個 X 的列”時,您都會看到這種情況。

當您擁有數萬個表時,這確實會導致真正的性能問題。 每個表都需要 MySQL 來維護內部數據結構、文件描述符、數據字典等。

還有實際的操作后果。 您真的想創建一個系統,每次新用戶注冊時都需要您創建一個新表嗎?

相反,我建議您使用MySQL Partitioning

以下是對表進行分區的示例:

CREATE TABLE statistics (
  id INT AUTO_INCREMENT NOT NULL,
  user_id INT NOT NULL,
  PRIMARY KEY (id, user_id)
) PARTITION BY HASH(user_id) PARTITIONS 101;

這為您提供了定義一個邏輯表的好處,同時還將該表划分為許多物理表,以便在查詢分區鍵的特定值時更快地訪問。

例如,當您像示例一樣運行查詢時,MySQL 僅訪問包含特定 user_id 的正確分區:

mysql> EXPLAIN PARTITIONS SELECT * FROM statistics WHERE user_id = 1\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: statistics
   partitions: p1    <--- this shows it touches only one partition 
         type: index
possible_keys: NULL
          key: PRIMARY
      key_len: 8
          ref: NULL
         rows: 2
        Extra: Using where; Using index

分區的 HASH 方法意味着將行按整數分區鍵的模數放置在分區中。 這確實意味着許多 user_id 映射到同一個分區,但每個分區平均只有 1/N 的行數(其中 N 是分區數)。 並且您使用恆定數量的分區定義表,因此您不必在每次獲得新用戶時擴展它。

您可以選擇最多 1024 個(或 MySQL 5.6 中的 8192 個)的任意數量的分區,但有些人報告說當分區數達到如此高時會出現性能問題。

建議使用質數分區。 如果您的 user_id 值遵循某種模式(例如僅使用偶數),則使用質數分區有助於更均勻地分布數據。


在評論中回復您的問題:

如何確定合理數量的分區?

對於 HASH 分區,如果您使用 101 個分區,就像我在上面的示例中顯示的那樣,那么任何給定的分區平均大約有 1% 的行。 你說你的統計表有 3000 萬行,所以如果你使用這種分區,你每個分區只有 30 萬行。 這對 MySQL 來說更容易閱讀。 您也可以(並且應該)使用索引——每個分區都有自己的索引,並且它只有整個未分區表的索引大小的 1%。

因此,如何確定合理的分區數量的答案是:整個表有多大,以及您希望分區平均有多大?

分區的數量不應該隨着時間的推移而增長嗎? 如果是這樣:我怎樣才能自動化?

如果您使用 HASH 分區,則分區數量不一定需要增加。 最終您可能總共有 300 億行,但我發現當您的數據量以數量級增長時,無論如何都需要一個新的架構。 如果您的數據增長那么大,您可能需要在多個服務器上進行分片以及分區到多個表中。

也就是說,您可以使用 ALTER TABLE 重新分區表:

ALTER TABLE statistics PARTITION BY HASH(user_id) PARTITIONS 401;

這必須重構表(就像大多數 ALTER TABLE 更改一樣),因此預計需要一段時間。

您可能希望監視分區中數據和索引的大小:

SELECT table_schema, table_name, table_rows, data_length, index_length
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE partition_method IS NOT NULL;

與任何表一樣,您希望活動索引的總大小適合您的緩沖池,因為如果 MySQL 必須在 SELECT 查詢期間交換部分索引進出緩沖池,則性能會受到影響。

如果您使用 RANGE 或 LIST 分區,則添加、刪除、合並和拆分分區更為常見。 http://dev.mysql.com/doc/refman/5.6/en/partitioning-management-range-list.html

我鼓勵您閱讀有關分區手冊部分,並查看這個不錯的演示文稿: 使用 MySQL 5.1 分區提高性能

這可能取決於您計划經常進行的查詢類型,確定的最佳方法是實現兩者的原型並進行一些性能測試。

話雖如此,我希望帶有索引的單個(大)表總體上會做得更好,因為大多數 DBMS 系統都經過了大量優化,可以處理查找數據並將數據插入到大表中的確切情況。 如果您嘗試制作許多小表以希望提高性能,那么您就在與優化器(通常更好)作斗爭。

另外,請記住,一張桌子在未來可能更實用。 如果您想獲得所有用戶的匯總統計信息怎么辦? 擁有 20 000 個表會使執行起來非常困難且效率低下。 也值得考慮這些模式的靈活性。 如果你這樣划分你的桌子,你可能會把自己設計成未來的一個角落。

具體例子:

我有一張關於用戶統計信息的表(20,000 個用戶和大約 3000 萬行)。 該表有大約 10 列,包括 user_id、動作、時間戳等。最常見的應用是:通過 user_id 插入數據和通過 user_id 檢索數據(SELECT 語句從不包括多個 user_id)。

做這個:

id INT UNSIGNED NOT NULL AUTO_INCREMENT,
 ...
PRIMARY KEY(user_id, id),
INDEX(id)

在 PK開始時使用user_id為您提供“參考位置”。 也就是說,一個用戶的所有行都聚集在一起,從而最大限度地減少 I/O。

PK末尾id是因為 PK 必須是唯一的。

看起來很奇怪的INDEX(id)是為了讓AUTO_INCREMENT開心。

抽象問題:

  • 永遠不要有多個相同的表。
  • 僅當滿足http://mysql.rjweb.org/doc.php/partitionmaint 中列出的用例之一時才使用PARTITIONing
  • PARTITIONed表需要的索引集與未分區的等效表不同。
  • 在大多數情況下,單個未分區的表是最佳的。
  • 使用查詢來設計索引。

Bill Karwins 的回答沒有什么可補充的。 但一個提示是:檢查是否始終需要完整詳細地提供用戶的所有數據。

如果您想提供使用情況統計信息或訪問次數或這些內容,您通常不會得到單個操作和秒的粒度,例如,從今天的角度來看 2009 年。 因此,您可以構建聚合表和存檔表(當然不是引擎存檔),以獲取有關操作庫的最新數據和舊操作的概覽。

我認為,舊的行為不會改變。

例如,您仍然可以使用存檔表中的 week_id 來詳細了解聚合。

代替每個用戶從 1 個表到 1 個表,您可以使用分區來達到中間某處的多個表/表大小比率。

您還可以保留用戶的統計信息,以嘗試將“活躍”用戶移動到 1 個表中,以減少隨着時間的推移您必須訪問的表的數量。

最重要的是,您可以做很多事情,但主要是您必須構建原型和測試,並且只需評估您所做的各種更改對性能的影響。

暫無
暫無

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

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