從SQL 語言, DB 和 開發人員之間對SQL的撰寫的目的和本質的理解就有不一樣,一個是要以邏輯爲基礎知足業務需求便可,性能方面的需求這變得不是核心人物,而DB 人員則對SQL的撰寫和優化做爲一個核心的目的,性能是重要的,因此矛盾就產生了.
sql
如何解決這樣的矛盾,其實平常無非幾個方法
數據庫
1 DB 懂得業務而且在項目之初就介入,在表設計和優化方前期就下功夫,避免開發和DB之間的矛盾,固然能作到這樣的單位少之又少,緣由很複雜,但大多不是技術上的問題.安全
2 在硬件上面作文章,軟件設計的很差,硬件上給力,什麼SSD ,大內存, 都給上,這樣雙方的矛盾也能緩解,所謂弄用錢辦的事情,都不是事情,但對於項目和開發,以及DB,都不是什麼好事,這些人都沒有進步,這樣的事情大部分發生在國企,或事業單位.微信
3 就是今天的要說,DB 若是管不了開發,項目,那有沒有方法經過本身的手段來挽救,你所管轄的系統.性能
自MYSQL 8.012 能夠開始進行相關的 INSERT ,UPDATE ,DELETE ,REPLACE,優化
提出了query rewrite plugin 組件. 在此以前組件僅僅支持SELECT 語句的變動.
.net
首先咱們先確認,當前的MYSQL 是否有相關的插件和支持,這裏使用的MYSQL8.019 official community 的版本,這幫
插件
show global variables like 'lc_messages_dir'; 設計
而後咱們將組件加載到當前的MYSQL中,到響應的目錄,直接執行 insert_rewriter.sql 加載到當前系統
3d
執行後咱們的MYSQL會多一個數據庫,query_rewrite
select plugin_name,plugin_status, plugin_version from information_schema.plugins where plugin_name='Rewriter';
在確認以上信息後,下面就能夠進行一些簡單的樣例
1 常常有人直接對數據庫中的大表進行操做,這樣的操做直接影響了系統的安全性,屬於須要防範和進行取消的操做,但實際上即便有了相關的數據庫審覈和數據庫的規範,但實際上仍是不能將這一行的行爲杜絕.
那下面的工做就能夠幫助到你,這裏咱們的employees 數據庫中有一個表dept_emp 表比較大3000萬數據,但常常有人 select * from dept_no 這個表而且沒有條件. 那咱們就能夠經過這個rewrite 的plug-in 將這一行的語句直接封殺.
insert into queery_rewrite.rewrite_rules (id,pattern_database,pattern,replacement) values (1,'employees','select * from dept_emp','select * from dept_emp limit 1');
咱們在所在的數據庫上直接執行上述語句,而且
call query_rewrite.flush_rewrite_rules();
執行上述存儲過程,讓上述規則生效.
在此查詢的時候,語句就不會將全部的記錄拋出了,而是直接替換這個語句變成 select * from dept_emp limit 1; 這樣的形式
那如此就完事了,固然沒有,若是他寫成這樣的形式,
select * from dept_emp limit 100000; 那就會顯示10萬條數據嗎? 顯然不是的咱們稍加處理,讓他這樣的操做也不能夠,固然事先要知道如此邏輯在業務中是能夠經過的.
insert into query_rewrite.rewrite_rules (id,pattern_database,pattern,replacement) values (2,'employees','select * from dept_emp limit ?','select * from dept_emp limit 10');
call query_rewrite.flush_rewrite_rules();
如此執行上述語句後,他在忙活也只能顯示10條數據.
這裏面 ? 問好表明一個變量, 也就是不管 limit 後面填寫什麼變量,最後都是變換成 select * from dept_emp limit 10;
那麼下面咱們模擬一個複雜的操做
舉例咱們下面的語句中咱們不想讓用戶使用 in 而是想使用 exists
update employees set hire_date = '1986-08-28' where emp_no in (
select b.emp_no from (select * from employees) as b where b.hire_date > '1986-06-26');
update employees set hire_date = '1986-08-28' where exists (
select * from (select * from employees) as b where b.hire_date > '1986-06-26');
在操做完畢後,咱們直接運行
下面的語句, 或者經過explain 來看都是執行了這個 in 的語句,但咱們打開general log後, 記錄的執行的語句
因此經過rewrite 這個MYSQL的功能,能夠將咱們對程序中的一些很差的寫法進行一個更改, 實際上執行的使咱們替換後的語句.
固然這樣的作法必須在驗證這樣的操做比原有操做性能更高,而且進行一段時間的驗證後,才能實現.
本文分享自微信公衆號 - AustinDatabases(AustinDatabases)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。