它是而不是可能爲視圖定義聲明一個索引。 (谷歌是對的)。
但是,您可以在88個表中的每一個上添加一個索引。創建哪些索引確實取決於數據分佈,基數以及最重要的是針對這些表運行的查詢。索引不是一個銀彈。對於某些查詢模式,沒有索引可以幫助。所以,在我們開始創建索引...
觀點在MySQL中是如何工作的通知發現性能問題
學習引用視圖定義在MySQL中被處理的查詢如何是關鍵瞭解爲什麼觀點可能會導致性能問題,從而引發未初始化的不知情。
這是一個太簡單的答案,以跳到「意見是壞」的流行。它並沒有真正回答爲什麼與觀點的表現被認爲是「壞」。
以下是一些漫步...並可以使用良好的編輯。
在老版本的MySQL中,視圖定義總是物化的。在MySQL白話中,它被稱爲派生表。當你理解操作的順序時,他們使用它的名字是有意義的。無論是內聯視圖(在查詢中用作行源的SELECT
語句)還是對存儲視圖的引用(作爲對象存儲在數據庫中的SELECT
語句),都會觀察到相同的行爲。
性能問題與處理外部查詢中的謂詞一起使用。在較早版本的MySQL中,外部查詢中的謂詞是從未將推入視圖定義中。如果視圖是內聯或存儲的,則無關緊要。
作爲一個簡化的演示,考慮這個查詢:
SELECT v.mycol
FROM (SELECT t.mycol
FROM bigtable t
) v
WHERE v.mycol = 'foo'
操作在MySQL的順序是先運行括號之間的查詢,並把它作爲物化派生表。性能是在做的順序
CREATE TEMPORARY TABLE v (mycol mydatatype);
INSERT INTO v (mycol) SELECT t.mycol FROM bigtable t;
對於滿足一些特定要求的小型表,MySQL將使用MEMORY引擎。如果一個表不符合要求,或者超過了一定的大小,那麼MySQL將它作爲MyISAM表格將其作爲一個磁盤關閉到磁盤。
該操作完成後,可以運行外部查詢。當這個運行時,v
可以像一個普通的表進行訪問:
SELECT v.mycol
FROM v
WHERE v.mycol = 'foo'
隨着該查詢,MySQL有評估mycol
爲每行v
(派生表),以確定是否行匹配或不。就性能而言,這會帶來傷害。
(具有最新版本的MySQL 5.7,優化器將(在某些情況下)實際上創建派生表的索引。在舊版本中,MySQL會從未創建一個派生表的索引。哎喲。
如果我們的查看查詢執行的是SELECT * FROM bigtable
(選擇每一列,那麼視圖有效地複製整個表。如果bigtable
中的行很大,並且該表包含大量的行,則這可能是一個昂貴的操作。
如果我們將該查詢定義作爲VIEW存儲在數據庫中,那麼相同的一組操作將發生每我們查詢視圖的時間。
我的意思是「推」謂詞「進入」查看查詢。
對比上面什麼用這樣的查詢情況:
SELECT v.mycol
FROM (
SELECT t.mycol
FROM bigtable t
WHERE t.mycol = 'foo'
) v
WHERE v.mycol = 'foo'
請注意,我們有一個WHERE
條款對內部查詢中,括號之間。 MySQL運行該內部查詢,它僅從bigtable
中檢索滿足WHERE
子句中該條件的行。如果這是相當有選擇性的,那麼行數可能是一個非常小的集合。通過這個內部查詢,MySQL優化器可以利用具有前導列mycol
的索引來有效地滿足查詢。如果mycol
是bigtable的PRIMARY KEY或UNIQUE KEY,那麼查詢最多隻返回一行。這是一個更小的派生表來實現。
而在此示例中,外部查詢的謂詞是多餘的。外部查詢中的WHERE
子句可以被刪除,我們仍然保證得到相同的結果。
在您的特定情況下,MySQL是有開88桌,獲得元數據鎖,並獲得表鎖(如果它的MyISAM)等
至於其他的答案(正確地)指出的那樣,您的查詢中的UNION
運算符正在導致「唯一排序」操作,以識別並從整個集合中刪除重複行。這可能是昂貴的。
TL; DR
BOTTOM LINE
創建視圖的定義是更可能創建出更大,更成問題的性能問題,不是什麼問題正在創建視圖定義解決。
就性能而言,使用包含每個表的查詢的謂詞的查詢會更好。假設你需要每列(你真的需要返回的每一列,或者你真的只需要其中的一個子集)
這個查詢將會運行得更快:
SELECT t01.* FROM mytable01 t01 WHERE t01.mycol = 'foo'
UNION ALL
SELECT t02.* FROM mytable02 t02 WHERE t02.mycol = 'foo'
UNION ALL
SELECT t03.* FROM mytable03 t03 WHERE t03.mycol = 'foo'
...
UNION ALL
SELECT t88.* FROM mytable88 t88 WHERE t88.mycol = 'foo'
這是特別是如果在88個表中的每一個表中,mycol
都有適當的索引。
當我有一個結合來自多個查詢的結果(但不包括88個表!)時,我通常會包含一個鑑別器列,這將允許我確定哪個查詢返回了該行。
SELECT 't01' AS q, t01.* FROM mytable01 t01 WHERE t01.mycol = 'foo'
UNION ALL
SELECT 't02' AS q, t02.* FROM mytable02 t02 WHERE t02.mycol = 'foo'
UNION ALL
SELECT 't03' AS q, t03.* FROM mytable03 t03 WHERE t03.mycol = 'foo'
...
UNION ALL
SELECT 't88' AS q, t88.* FROM mytable88 t88 WHERE t88.mycol = 'foo'
從在結果(q
)我可以確定哪個查詢返回的行第一列。
問題是什麼?我想你問了一些提示。我希望我已經給你一些要考慮的事情。
我的第一個問題是,「爲什麼你有那麼多相同的桌子?」 –
你的看法是否真的使用'union'?既然你應該允許使用'union all'的表格之間的重複,這也應該是一個巨大的速度提升。 – Mureinik
創建視圖定義作爲問題的解決方案通常會引入比原始問題更大的問題。這不是要跳過「觀點不好」的風潮,而是創建和使用視圖*而不去理解*如何在MySQL中處理這些問題會導致*顯着的性能問題。 (我在答案中更詳細地解決了這個問題。) – spencer7593