1. 程式人生 > >【原】對MYSQL下視圖的一些總結

【原】對MYSQL下視圖的一些總結

訪問者 虛表 不起作用 圖片 rom -- 除了 出現 img

註:本文使用mysql5.5版本為例。 做過數據庫開發的同學,對視圖(VIEW)應該不會陌生。 我接觸視圖最多的應用場景有兩個: 1)出於權限問題,為了限制訪問者看到過多的表字段(或內容),就建立一個視圖供TA使用。 2)也可以為了查詢方便,將多張表合並到一個視圖裏使用。 比如,我最近遇到一個這樣的需求: 有四種用戶類型的表,有部分相同的信息,當然也會有很多不相同的字段: T_USER_PERSON(ID, PERSON_NAME, CREATE_TIME, …) T_USER_TEAM(ID, TEAM_NAME, CREATE_TIME, …) T_USER_COMPANY(ID, COMPANY_NAME, CREATE_TIME, ...) T_USER_ORGANIZATION(ID, ORGANIZATION_NAME, CREATE_TIME, ...) 還有一張業務表,匯集了這四種用戶分別創建的業務數據: T_BUSSINESS(ID, USER_ID, USER_TYPE, CONTENT, ...) USER_TYPE 是枚舉類型:PERSON, TEAM, COMPANY, ORGANIZATION 由USER_ID和USER_TYPE來關聯哪類的哪個用戶,創建了這條業務數據。 關系圖大概是這樣的: 技術分享圖片

我第一個就想到了使用視圖?建立一個視圖統一管理所有用戶,再跟業務表關聯查詢,業務邏輯多麽清晰! 於是,我建立這張視圖,如下: CREATE OR REPLACE VIEW VIEW_ALL_TYPE_USER as select id id, PERSON_NAME user_name, ‘PERSON‘ user_type, create_time create_time from T_USER_PERSON UNION ALL select id as id, COMPANY_NAME as user_name, ‘COMPANY‘ as user_type, create_time create_time from T_USER_COMPANY UNION ALL select id as id, ORGANIZATION_NAME as user_name, ‘ORGANIZATION‘ as user_type, create_time create_time from T_USER_ORGANIZATION UNION ALL select id as id, TEAM_NAME as user_name, ‘TEAM‘ as user_type, create_time create_time from T_USER_TEAM; 改變之後的關系圖大概是這樣的: 技術分享圖片

聯合查詢的sql語句如下: select b.id, b.user_id, v.user_name, b.content from T_BUSSINESS b left join VIEW_ALL_TYPE_USER v ON b.user_id=v.user_id and b.user_type=v.user_type order by b.id desc 看起來很簡潔,但是運行起來就慢得要死。其實數據量並不大,用戶總共大概有12萬,業務數據大概1400條。可是,經過視圖和表的關聯查詢,速度是不可以忍受的,我想,這是多重笛卡爾積的結果吧。 除了聯合查詢效率低的問題,視圖還不能建立索引
,沒辦法有效提高查詢效率。 經過再三權衡,我決定放棄視圖,寧可使用稍微復雜一些的case-then語句來實現。效果還是可以的。 select b.id, b.user_id, b.user_type, case b.user_type when ‘PERSON‘ then (select USER_NAME from T_USER_PERSON u where u.id=b.user_id) when ‘ENTERPRISE‘ then (select COMPANY_NAME from T_USER_COMPANY o where o.id=b.user_id) when ‘CHARITY‘ then (select ORGANIZATION_NAME from T_USER_ORGANIZATION c where c.id=b.user_id) when ‘TEAM‘ then (select TEAM_NAME from T_USER_TEAM t where t.id=b.user_id) end as user_name, b.content from T_BUSSINESS b order by b.id desc 但是,這樣的話,存在一個問題: 如果用別名作為查詢條件,會出現錯誤:Unknown column ‘user_name‘ in ‘where clause‘ 1)把別名的查詢條件放在table後面: http://bbs.csdn.net/topics/320013418 這種辦法對我不起作用,不知道是否是版本的問題…… 2)用一個select包起來: http://blog.csdn.net/testcs_dn/article/details/69400269 註意:每個table,包括最終()起來的虛表都要起個別名 3)在查詢條件裏使用完整的case-then: https://www.cnblogs.com/xiandedanteng/archive/2013/09/22/3333469.html 在本文中的sql語句應該是: select b.id, b.user_id, b.user_type, case b.user_type when ‘PERSON‘ then (select USER_NAME from T_USER_PERSON u where u.id=b.user_id) when ‘ENTERPRISE‘ then (select COMPANY_NAME from T_USER_COMPANY o where o.id=b.user_id) when ‘CHARITY‘ then (select ORGANIZATION_NAME from T_USER_ORGANIZATION c where c.id=b.user_id) when ‘TEAM‘ then (select TEAM_NAME from T_USER_TEAM t where t.id=b.user_id) end as user_name, b.content from T_BUSSINESS b where case b.user_type when ‘PERSON‘ then (select USER_NAME from T_USER_PERSON u where u.id=b.user_id) when ‘ENTERPRISE‘ then (select COMPANY_NAME from T_USER_COMPANY o where o.id=b.user_id) when ‘CHARITY‘ then (select ORGANIZATION_NAME from T_USER_ORGANIZATION c where c.id=b.user_id) when ‘TEAM‘ then (select TEAM_NAME from T_USER_TEAM t where t.id=b.user_id) end like ‘測試%‘ order by b.id desc ------------------- 但是,好景不長,又遇到了問題…… 新的需求來了,在外面又多了一層查詢: 有多種相似的業務,想要放在一起進行排序展示。(這回我學“聰明”了,不考慮視圖了)這樣,就需要嵌套兩層case-then語句……,先不考慮效率問題,這樣冗長的SQL的可讀性和維護性也太差了吧? 又經過再三權衡,我還是決定在業務表裏增加一個user_name字段,雖然這是個冗余字段,但會使邏輯更簡單,更易於維護。至於user_name數據一致性的問題,解決方法有很多:觸發器/異步通知/同步更新等等,都可以實現。畢竟user_name並不是經常修改的。 最終的業務表是這樣的(當然,其他的業務表也都增加了USER_NAME字段): T_BUSSINESS(ID, USER_ID, USER_TYPE, USER_NAME, CONTENT, ...) 最後看起來大概是這個樣子的: 技術分享圖片

至少,以我目前有限的認識,這樣做是最佳方案,希望有更好方法的同學不吝賜教。

【原】對MYSQL下視圖的一些總結