首先祝你們新年快樂,身體健康,萬事如意。
通常來講一個系統最早出現瓶頸的點極可能是數據庫。好比咱們的生產系統併發量很高在跑一段時間後,數據庫中某些表的數據量會愈來愈大。海量的數據會嚴重影響數據庫的讀寫性能。
這個時候咱們會開始優化系統,通常會通過這麼幾個過程:sql
對於第五點優化方案咱們來細說一下。分表分庫一般有兩種拆分維度:1.垂直切分,垂直切分每每跟業務有強相關關係,好比把某個表的某些不經常使用的字段遷移出去,好比訂單的明細數據能夠獨立成一張表,須要使用的時候纔讀取 2.水平切分,好比按年份來拆分,把數據庫按年或者按某些規則按時間段分紅多個表。
拆分表以後每一個表的數據量將會變小,帶來的好處是不言而喻的。不論是全表掃描,仍是索引查詢都會有比較高的提高。若是把不一樣的表文件落在多個磁盤上那數據庫的IO性能還能進一步提升。
若是純手工拆分,好比按年份拆分紅多個表,那麼上層業務代碼也得進行調整。每次讀寫都得判斷該使用哪張表。若是是跨多個年份的分頁查詢更加難搞。人肉分表基本上不可能實現的,對於上層編碼簡直是個噩夢。因此針對分表分庫咱們一般會使用某些中間件,好比Mycat,Sharding-JDBC等中間件。使用這些組件確實能實現分表分庫,而且對業務層代碼屏蔽了數據庫架構的改動,可是配置略顯麻煩。若是你使用的是SQL Server數據庫,而且目前還不須要分庫,只須要分表,那麼其實使用內置的分區表功能是最簡單的方案。只須要打開SQL Server Management Studio簡單設置幾下就能夠了,對於你上層應用徹底是無感的,你的代碼、數據庫鏈接串都不須要改動。
如下咱們經過2個簡單的測試,來簡單的演示下如何進行表分區操做,以及測試下分區先後性能變化。數據庫
咱們的測試方案:新建一張logs表,按年份寫入數據。2019年寫入1000000數據,2020年也寫入100000數據。爲了加快寫入的速度,每一個年份並行10個線程同時寫,每一個線程寫100000數據,一共1000000數據。而後把logs表改爲分區表再用一樣的方式寫入2000000數據。記錄耗時 比較兩次的耗時。
硬件爲一臺14年產的筆記本,OS爲win10。掛載2塊硬盤,1塊爲5400轉的機械硬盤,1塊爲15年加的SSD。磁盤性能能夠說極爲垃圾。未分區時表文件會落在機械硬盤上。緩存
使用腳本建表:架構
CREATE TABLE [dbo].[logs]( [id] [uniqueidentifier] NOT NULL, [log_txt] [varchar](200) NULL, [log_time] [datetime] NULL, CONSTRAINT [PK_logs] PRIMARY KEY CLUSTERED ( [id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] )
新建一個控制檯程序編寫代碼:併發
class Program { static void Main(string[] args) { Console.WriteLine("Hello World!"); Task.Run(() => { InsertData(2019); }); Task.Run(() => { InsertData(2020); }); Console.ReadLine(); } static void InsertData(int year) { var tasks = new List<Task>(); Stopwatch sw = new Stopwatch(); sw.Start(); for (int i = 0; i < 10; i++) { tasks.Add(Task.Run(()=> { using (var conn = new SqlConnection()) { conn.ConnectionString = "Persist Security Info = False; User ID =sa; Password =dev@123; Initial Catalog =fq_test; Server =.\\mssql2016"; conn.Open(); int index = 0; for (int j = 0; j < 100000; j++) { var logtime = new DateTime(year, new Random().Next(1, 12), new Random().Next(1, 28)); conn.Execute("insert into logs2 values (newid(),'下訂單',@logtime)", new { logtime }); Console.WriteLine("logtime:{0} index {1}", logtime, index++); } } })); } Task.WaitAll(tasks.ToArray()); sw.Stop(); Console.WriteLine("Year {0} complete , total time: {1}.", year, sw.ElapsedMilliseconds); } }
寫完2000000數據耗時1369454毫秒。dom
把一個表設置爲分區表大概有5個步驟:ide
如下演示下如何使用SQL SERVER Management Studio管理器進行表分區:
選中數據庫=>屬性=>文件組,添加group1,group2兩個文件組。
選中數據庫=>屬性=>文件。添加file1,文件組選group1,路徑選擇一個文件目錄。這裏選擇E盤data目錄。添加file2,文件組選擇group2,路徑選擇一個文件目錄。這裏選擇X盤的data目錄。這樣當分區的時候數據就會落在這2個目錄下。這裏的路徑能夠選擇在同一個硬盤,可是爲了更高的讀寫性能,若是有條件建議直接指定在不一樣的硬盤下。
選中logs表=>存儲=>建立分區,啓動分區嚮導工具。
新建一個分區函數,點擊下一步。
新建一個分區方案,點擊下一步。
選擇一個分區列,數據會根據該列進行水平拆分。這裏選擇logtime,由於時間是比較適合水平切分的一個維度。
值得數據拆分的範圍。範圍選擇「右邊界」。右邊界跟左邊界的差別在於對邊界值的處理。右邊界是<,左邊界是<=,也就是包含邊界值。
咱們這裏設置group1存儲2019的數據,group2存儲2020的數據。因此group1的邊界值設置爲2020-01-01,group2的邊界值設置爲2021-01-01 。
設置完是這個樣子,須要3個文件組。當出現不在group1,group2範圍內的數據就會存儲在第三個文件組內。
建好分區函數、分區方案後,能夠選擇生成腳本或者當即執行。這裏選擇「當即執行」。當執行完成後,表裏的數據會按照分區方案設置的邊界分散到多個文件上。函數
先清空logs表全部的數據,而後使用一樣的代碼進行測試。測試結果顯示寫完2000000數據耗時:568903毫秒。能夠看到數據庫寫性能大副提升,大概提升了1倍不止的性能。這也比較符合兩塊磁盤同時IO的預期。工具
咱們的測試方案:新建一張log2表,使用上面的代碼按年份寫入2000000數據。而後使用select語句同時讀取2019,2020年的數據。把log錶轉換成分區表,從新測試select的時間。比較兩次讀取數據的時間。
sql語句:性能
select * from log2 where (logtime > '2019-05-01' and logtime < '2019-06-01') or (logtime > '2020-05-01' and logtime < '2020-06-01')
首先在未分區的表上測試查詢性能,花費時間爲3s。
把表按前面的方法進行分區拆分,查詢花費時間爲1s。讀性能大概爲未分區時的3倍。
通過簡單的測試,SQL Server的分區表功能能大副提升數據庫的讀寫性能。經過SQL Server Management Stduio的簡單設置就能夠對數據庫表進行分區操做,而且對應用層的代碼徹底是無感的,比用分表分庫中間件來講簡單多了。