軟體開發(軟件開發)

網智數位主要提供套裝及客製化的軟體系統解決方案,專為客戶量身訂做客製化的軟體,達成客製化、智慧化及網路化的管理功能。

室內設計、裝潢、窗簾報價估算軟體

網智數位主要提供套裝及客製化的軟體系統解決方案,針對室內設計師、木工、裝潢業產業,量身訂做客製化的軟體,達成客製化、智慧化及網路化的商用軟體。

商用軟體-客製化設計

網智數位主要提供套裝及客製化的軟體系統解決方案,專為客戶量身訂做客製化的軟體,達成客製化、智慧化及網路化的管理功能。

IOT 物聯網-系統開發

根據客戶實際狀況,結合雲端與載具進行客製化物聯網IOT導入與軟體開發

雲端VPS虛擬主機租用

我們的雲端VPS虛擬主機是採用雲端(虛擬化)技術所開發之全新雲端伺服器服務,可以選擇多種作業系統(Windows、Linux等),客戶可載入自訂的應用環境,執行自己所要提供的網路服務,我們的雲端服務可為您的網站提供最完美的解決方案。

ERP軟體客製化導入

ERP軟體客製化導入,室內設計、營造業、裝潢、木作工程、系統櫃工程、會計系統,全面提升公司管理營運效率。

搜尋引擎最佳化SEO

搜尋引擎最佳化(SEO)不僅能提高網站在搜尋結果的排名,更能帶來大量對我們產品或服務真正有需求的訪客。SEO 最棒的特質之一就是不像廣告一樣亂槍打鳥而導致用戶的反感,反而更能提升點閱率跟成交率喔。

服務宗旨

網智數位主要提供套裝及客製化的軟體系統解決方案,專為客戶量身訂做客製化的軟體,達成客製化、智慧化及網路化的管理功能。

我們的成立宗旨就是要以最猛的IT技術讓這個世界更Smart,在我們貫徹我們裡想的同時,我們希望可以把我們所開發的系統帶給台灣的中小企業,除了要推薦好的東西之外,我們也希望做點改變,所以我們的第一目標就是要使用最好用的系統再加上您寶貴的創意,不僅僅可以節省你大量的荷包,還可以有一個像樣的網站。我們可以幫你做的有

企業管理
  • 策略管理
  • 目標管理
  • 行銷管理
  • 財會管理
  • ERP導入
  • 企業流程自訂
資訊管理
  • 網站架設
  • 虛擬化/雲端架設
  • 主機代管
  • 私有雲建制與導入
軟體開發
  • UML設計
  • 版本控管
  • 企業軟體開發
  • APP開發
  • 網頁設計
資訊安全
  • 網頁弱點掃描
  • 主機弱點掃描
  • 木馬檢測
  • 資安鑑識
  • 設計網路架構
  • 資安監控
行銷
  • 關鍵字SEO
  • 社群網路行銷
  • 部落格行銷
  • FaceBook 粉絲團
其他
  • 協助企業申請Google Email
好玩工具開發

講出你的創意吧!沒有甚麼是資訊辦不到的

顯示具有 SQL SERVER 標籤的文章。 顯示所有文章
顯示具有 SQL SERVER 標籤的文章。 顯示所有文章

2014年11月9日 星期日

[Entity Framework] 效能深入探討(一)

      作者我在使用Entity Framewok開發時,最常聽到的一句話就是,Entity Framework 是否"好像"效能很慢喔,在微軟剛推出Entity Framewok前(事實上微軟真的這方面算是進展很慢,其他程式陣營早就有相關的Framework,例如 Java 的 Hibernate,不過後來真的速度改版的很迅速,微軟都這樣玩法),我會很肯定的回答"是",如果當時要採用 Entity Framewok時,我想可能最大的益處就是可以在程式開發過程時,比較可以使用"概念模型"(Conceptual Model)以及 OOP(物件導向)的思維導向,也可以避免程式開發人員在寫程式盡可能避免了 SQL Script,當然也避免了一些開發人員真的不太會寫 SQL,相信我真的還遇到過,不過隨著Entity Framewok 發展到 Version 6 UP.., 我相信大多數是可以依靠 EF(Entity Framewok),而且開發速度的優勢已經是大多數優先考慮採用的原因,尤其現在到處都是 WEB API、MVC架構(EF歸於 Model  Layer),我們更需要好好學習一下,所以我打算寫幾篇關於 EF效能的底層技術與原理,畢竟 Entity Framewok 雖然把底層 SQL的工作,都幫你處理好,但你知道為何有時似乎效能真的好像還是很慢,所以我想直接跟讀者說一些原理,這也是市面上書籍似乎都沒在探討的.....

     我先在此介紹一個Entity Framework 的術語 Lazy Load , 它代表 延遲載入 預設值是成立(true)  。為了解釋何謂Lazy Load,我自己帶入一個案例來進行解釋
例如在我們 CRM系統裏有 [客戶類型]類別 (CustCate Class) , 而每個[客戶類型]可以有多個興趣的[客戶]類別 (Customer Class),此時很典型存在所謂的一對多 One-To-Many 的模型 ;而每個[客戶]類別也可以記錄此客戶相關的[客戶事件]類別(CustomerEvent Class)
,下面我列出了案例模型圖


根據上述模型我們來實作一個 Code First EF Model 
實作 Customer 、CustCate、CustomerEvent Class Code ....

    [Table("Customer")]
    public partial class Customer
    {
        public Customer()
        {
            CustomerEvent = new HashSet<CustomerEvent>();
        }

        [Key]
        [StringLength(15)]
        public string No { get; set; }

        [StringLength(10)]
        public string CName { get; set; }

        [StringLength(10)]
        public string ENmae { get; set; }

        [StringLength(10)]
        public string CateCode { get; set; }

        public virtual CustomerCate CustomerCate { get; set; }

        public virtual ICollection<CustomerEvent> CustomerEvent { get; set; }
    }

    
    [Table("CustomerCate")]
    public partial class CustomerCate
    {
        public CustomerCate()
        {
            Customer = new HashSet<Customer>();
        }

        [Key]
        [StringLength(10)]
        public string Code { get; set; }

        [Required]
        [StringLength(15)]
        public string Name { get; set; }

        public virtual ICollection<Customer> Customer { get; set; }
    }

    [Table("CustomerEvent")]
    public partial class CustomerEvent
    {
        [Key]
        [StringLength(36)]
        public string EventID { get; set; }

        [StringLength(15)]
        public string CustNo { get; set; }

        [Required]
        [StringLength(300)]
        public string Desc { get; set; }

        public DateTime CreateDate { get; set; }

        public virtual Customer Customer { get; set; }
    }

     
實作一個繼承 DbContext 的 EF 存取容器

    public class CRMEF : DbContext
    {
        public CRMEF()
            : base("name=EF")
        {
        }

        public virtual DbSet<Customer> Customer { get; set; }
        public virtual DbSet<CustomerCate> CustomerCate { get; set; }
        public virtual DbSet<CustomerEvent> CustomerEvent { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Customer>().ToTable("Customer");
            modelBuilder.Entity<CustomerCate>().ToTable("CustomerCate");
            modelBuilder.Entity<CustomerEvent>().ToTable("CustomerEvent");

            modelBuilder.Entity<Customer>().HasMany(e => e.CustomerEvent)
                                           .WithOptional(e => e.Customer)
                                           .HasForeignKey(e => e.CustNo);

            modelBuilder.Entity<CustomerCate>().HasMany(e => e.Customer)
                                               .WithOptional(e => e.CustomerCate)
                                               .HasForeignKey(e => e.CateCode);

            base.OnModelCreating(modelBuilder);
        }
    }


我也設計一個前端界面

在寫入測試資料 Button,先寫入基本資料以利後面的解說
private void btnTestData_Click(object sender, EventArgs e)
{
  try
   {
       using (CRMEF ef = new CRMEF())
        {
             CustomerCate cate1 = new CustomerCate() { Code = "Retail", Name = "零售商" };
             CustomerCate cate2 = new CustomerCate() { Code = "Direct", Name = "直客" };
             CustomerCate cate3 = new CustomerCate() { Code = "EC", Name = "網路消費者" };

             Customer cust1 = new Customer() { CustomerCate = cate1, No = "001", CName = "智慧零售商", ENmae = "Smart" };
             CustomerEvent custEvent1 = new CustomerEvent() { Customer = cust1, EventID = Guid.NewGuid().ToString(), Desc = "詢問新產品目錄", CreateDate = DateTime.Now };
             ef.CustomerEvent.Add(custEvent1);
             CustomerEvent custEvent2 = new CustomerEvent() { Customer = cust1, EventID = Guid.NewGuid().ToString(), Desc = "購買10套 網智數位 CRM 套裝軟體", CreateDate = DateTime.Now };
             ef.CustomerEvent.Add(custEvent2);
             Customer cust2 = new Customer() { CustomerCate = cate2, No = "002", CName = "柯P", ENmae = "柯P" };
             CustomerEvent custEvent3 = new CustomerEvent() { Customer = cust2, EventID = Guid.NewGuid().ToString(), Desc = "尋找物聯網的合作廠商", CreateDate = DateTime.Now };
             ef.CustomerEvent.Add(custEvent3);
             Customer cust3 = new Customer() { CustomerCate = cate3, No = "003", CName = "連勝吻", ENmae = "連勝吻" };
             CustomerEvent custEvent4 = new CustomerEvent() { Customer = cust3, EventID = Guid.NewGuid().ToString(), Desc = "網路行銷推廣", CreateDate = DateTime.Now };
             ef.CustomerEvent.Add(custEvent4);

             ef.SaveChanges();
             MessageBox.Show("Test Insert OK");
         }
    }
    catch { }
 }

執行後,我們可以看到後端資料庫就存在一下資料


現在有了案例的資料後,我就可以開始解釋何謂 Lazy Loading,在上述案例我們如果需要列出所有客戶以及他相關的活動事件,以及此客戶歸屬的類別,我把它寫在 "Lazy Loading" Button Click:

  1. private void btnLazyLoading_Click(object sender, EventArgs e)
  2. {
  3. this.richTextBox1.Clear();
  4. this.richTextBox1.AppendText("使用 Lazy Loading 讀取,系統預設行為! \r\n");
  5. this.richTextBox1.AppendText("------------------------------------------------------------------------- \r\n");

  6. using (CRMEF ef = new CRMEF())
  7. {
  8. var customers = ef.Customer;

  9. foreach (var cust in customers)
  10. {
  11. this.richTextBox1.AppendText("客戶編號 : " + cust.No + " 客戶姓名 :" + cust.ENmae + "\t  類型 :" + cust.CustomerCate.Name + "\r\n");
  12. this.richTextBox1.AppendText("--------------------------------事件記錄------------------------------------ \r\n");

  13. foreach (var evt in cust.CustomerEvent)
  14. {
  15. this.richTextBox1.AppendText(evt.Desc + "\r\n");
  16. }

  17. this.richTextBox1.AppendText("\r\r\n");
  18. }
  19. }
  20. }
執行後結果如下

看樣子結果都是沒錯的,但各位我要告訴你們,你知道 上述結果 Entity Framewok 是幫我們產生多少次 SQL語法嗎? , 以及來回跟後端資料庫查詢幾次嗎?
答案是 7 次 ,也就是說白話一點,就是 EF要來回跟後端資料庫溝通要得資料7次,才可以把我們要呈現的資料,完全取回來,各位如果客戶資料不是現在案例的3筆,而100筆...1000筆....甚至 10000筆以上呢?

我分別把我追蹤後的SQL 語法寫下:
第 1 次 SQL :
SELECT
    [Extent1].[No] AS [No],
    [Extent1].[CName] AS [CName],
    [Extent1].[ENmae] AS [ENmae],
    [Extent1].[CateCode] AS [CateCode]
    FROM [dbo].[Customer] AS [Extent1]

第 2 次 SQL :
exec sp_executesql N'SELECT
    [Extent1].[Code] AS [Code],
    [Extent1].[Name] AS [Name]
    FROM [dbo].[CustomerCate] AS [Extent1]
    WHERE [Extent1].[Code] = @EntityKeyValue1',N'@EntityKeyValue1 nvarchar(10)',@EntityKeyValue1=N'Retail'

第 3 次 SQL :
exec sp_executesql N'SELECT
    [Extent1].[EventID] AS [EventID],
    [Extent1].[CustNo] AS [CustNo],
    [Extent1].[Desc] AS [Desc],
    [Extent1].[CreateDate] AS [CreateDate]
    FROM [dbo].[CustomerEvent] AS [Extent1]
    WHERE [Extent1].[CustNo] = @EntityKeyValue1',N'@EntityKeyValue1 nvarchar(15)',@EntityKeyValue1=N'001'

第 4 次 SQL :
exec sp_executesql N'SELECT
    [Extent1].[Code] AS [Code],
    [Extent1].[Name] AS [Name]
    FROM [dbo].[CustomerCate] AS [Extent1]
    WHERE [Extent1].[Code] = @EntityKeyValue1',N'@EntityKeyValue1 nvarchar(10)',@EntityKeyValue1=N'Direct'

第 5 次 SQL :
exec sp_executesql N'SELECT
    [Extent1].[EventID] AS [EventID],
    [Extent1].[CustNo] AS [CustNo],
    [Extent1].[Desc] AS [Desc],
    [Extent1].[CreateDate] AS [CreateDate]
    FROM [dbo].[CustomerEvent] AS [Extent1]
    WHERE [Extent1].[CustNo] = @EntityKeyValue1',N'@EntityKeyValue1 nvarchar(15)',@EntityKeyValue1=N'002'

第 6 次 SQL :
exec sp_executesql N'SELECT
    [Extent1].[Code] AS [Code],
    [Extent1].[Name] AS [Name]
    FROM [dbo].[CustomerCate] AS [Extent1]
    WHERE [Extent1].[Code] = @EntityKeyValue1',N'@EntityKeyValue1 nvarchar(10)',@EntityKeyValue1=N'EC'

第 7 次 SQL :
exec sp_executesql N'SELECT
    [Extent1].[EventID] AS [EventID],
    [Extent1].[CustNo] AS [CustNo],
    [Extent1].[Desc] AS [Desc],
    [Extent1].[CreateDate] AS [CreateDate]
    FROM [dbo].[CustomerEvent] AS [Extent1]
    WHERE [Extent1].[CustNo] = @EntityKeyValue1',N'@EntityKeyValue1 nvarchar(15)',@EntityKeyValue1=N'003'


這就是 Entitfy Framework 的預設行為 Lazy Loading , 上述 C# 語法我們先列舉了所有客戶的清單,此時 EF 就會產生 第一個 SQL 語法 是讀取後端 [dbo].[Customer] Table 的 SQL ,
而我們再依序根據每筆客戶分別讀取了客戶類型,此時 EF 又會去跟後端資料庫要求讀取 [dbo].[CustomerCate] Table ,所以有幾筆客戶資料,他就會來回跟資料庫讀取 [dbo].[CustomerCate] Table,各位這就是效能瓶頸所在
接下來我們繼續讀取每筆客戶的系統事件,此時 EF 又要懶惰 (Lazy Loading)的再去跟後端資料庫取得  [dbo].[CustomerEvent] 資料表,看吧!,系統如果資料量大一點,這樣大部分人使用 EF (Entitfy Framework) ,一定死了,被客戶抱怨死了,
此時通常工程師或開發人員就會抱怨 Entity Framewok好爛,效能好差,還是用ADO.Net好....這也是我公司工程師常跟我說類似的話,但如果你知道底層的原理,這都是可以操控自如的,完全可以任意操控EF,使它可以不用笨到來來回回奔走,
至於如何做呢? 就讓我留著下一回好好地告訴大家。。。。

2014年10月29日 星期三

Entity Framework 實戰 - Table Per Hierarchy Inheritance (TPH)實作

      今天我想抽空來寫篇關於 .Net EntityFramework 與 資料庫單一資料表(Table)的實作,這次實作機制方法為 Table Per Hierarchy Inheritance(TPH),顧名思義就是在底層資料庫的一個資料表對應了程式的資料模型多個實體,
我直接舉個例子來解釋資料庫與領域模型間的圖型。

資料庫 Table 圖例

然而在系統設計時,領域模型我們採取了一下設計


在上圖系統領域模型中, Media 為父類別 (Parent Class) ,而 Article 與 Video、Photo皆為繼承 Media 父類別的子類別(Child Class)


PS.注意,在 Media 類別,並沒有 Media 資料表的欄位 MediaType , 而 MediaType欄位的值在資料表是用來識別被繼承的子類別是屬於那個型別,
如 MediaType = "Article" , 此時代表為 Article Class ,依次為 MediaType = "Video" 代表為 Video Class ; MediaType = "Photo" 代表為 Photo Class 。

現在我開始撰寫 Media 、Article 、Video、Photo Class Code


因為 我採用 Code-First 的方式去實作 EntityFramework ,所以底下我設計一個 DBEntities Class ,並讓它繼承了 DbContext ,
這樣後續我就可以透過 DBEntitis 去處理後續的實體增修 CRUD。

上述步驟都完成後,接下來可以來測試透過 DBEntities 來進行新增并實際寫入資料表。
在這邊我利用 Windows Form 當做前端界面來實作


而在 寫入(存檔)的  Button  ,我寫了以下程式
    1:          private void button1_Click(object sender, EventArgs e)  
    2:         {  
    3:             //進行存檔
    4:             using(var context = new DBEntities())  
    5:             {  
    6:                 Article article = new Article() { Title = "網智數位行銷手冊秘笈", MediaID = "001" };  
    7:                 context.Media.Add(article);  
    8:   
    9:                 Video video = new Video() { Title = "網智ERP教學影片", MediaID = "002" };  
   10:                 context.Media.Add(video);  
   11:   
   12:                 Photo photo = new Photo() { Title = "網智數位設計", MediaID = "003" };  
   13:                 context.Media.Add(photo);  
   14:   
   15:                 context.SaveChanges();  
   16:   
   17:             }  
   18:         }  

點擊 寫入(存檔)Button後,此時在去後端資料庫檢查,我們可以看到結果如下

此時,資料表正確無誤的寫入 3 筆資料列,並且 MediaType 欄位,也會自動寫入對應的值(Article、Video、Photo)。




網智數位-軟體開發


2014年3月14日 星期五

5個自我檢視資料庫之安全性的方法



資料竊取越來越普遍,黑市裡信用卡資料的價錢從2006年一筆10元變成2009年幾毛錢。客戶對於電子商務、網路銀行與其他電子商業活動失去信心。同時駭客竊取資料的方法也越來越聰明,造成越來越多企業成為他們的犧牲品。至2009年時法令與法規以更嚴格地保護消費者,但仍不斷發生新的事件。在Verizon Business Data Breach Investigations Report報告中,研究過去五年內的600個事件,其中SQL Injection是單一攻擊中獲取大量資料的手法。

這個結果並不令人驚訝!若設計網站應用程式的成員不瞭解SQL Injection攻擊時,是很容易發生的。

何謂SQL Injection?
SQL Injection 應稱為SQL 指令植入式攻擊,主要是屬於 Input Validation 的問題。中文翻譯為『資料隱碼』攻擊。SQL Injection 攻擊法並非植入電腦病毒,它是描述一個利用寫入特殊 SQL 程式碼攻擊應用程式的動作。換言之,只要提供給使用者輸入的介面,又沒有做到相當嚴密的輸入資料型態管制,就有可能會遭受這種行為的攻擊。

SQL Injection攻擊可能會對企業造成重大與昂貴的損失。攻擊的目標是資料庫,其中儲存了員工、客戶的資料。這類型的攻擊利用應用程式中的漏洞,操作從瀏覽器輸入的SQL查詢。 在SQL Injection攻擊中,惡意使用者可發送任意輸入至伺服器且假冒web應用程式產生與原先不同的SQL描述。

因此資料庫伺服器會執行並取得與原先不同的結果。SQL Injection攻擊是最常對資料庫獲得未經授權的存取與資料操作。

如果不確定自己的資料庫安不安全或有沒有被入侵成功建議可以按照以下的五個作法自行檢視。


1.查詢SQL Server系統內帳號資訊

如果不幸被SQL Injection 很有可能會被駭客偷偷新增一個sa權限的帳號,即便未來SQL Injection漏洞被修復了,駭客可能還是可以透過其他管道連到資料庫,等於變相開了一個洞給駭客使用,所以我們先來查詢資料庫裡的所有使用者,是否有異常帳號存在。

select * from sysusers

可在結果欄位按滑鼠右鍵選擇「儲存結果」,將檔案匯出進行分析。




2.檢視交易紀錄檔

Transaction 一觸發會建立一個暫時性 Log ,暫存性Log會記錄交易中,修改資料的過程和內容,在自我檢查時建議也可以利用 Transaction Log Viewer 工具看看交易記錄檔中是不是有些惡意的SQL 語法,去Google就可以找到類似的工具,不過都是要錢的,備份方式如下。

—UI資料庫備份
BACKUP DATABASE [Arcsight] TO  DISK = N'D:\Arcsight.bak

(請自行修改資料庫名稱及備份路徑)

—UI交易記錄檔備份
BACKUP LOG [Arcsight] TO DISK = N'D:\Arcsight.bak' WITH NO_TRUNCATE
(請自行修改資料庫名稱及備份路徑)


或可以使用SQL Server Management Studio 圖形介面中設定備份


選擇完整備份


備份完整備份後在選擇交易記錄備份




3.停用系統擴充預存程序

檢查是否有啟用xp_cmdshell
系統延伸預存程序是存儲在SQLServer中的預先寫好的SQL語句集合, 其中危險性最高的程序就是xp_cmdshell了,它可以執行操作系統的任何指令,如果被 SQL Injection 駭客就可透過 xp_cmdshell 取得整台電腦的控制權。

檢測語法:
SELECT * FROM sys.configurations WHERE [name]='xp_cmdshell' ORDER BY name 

如果value = 1代表有啟用
 -- 建議關閉 xp_cmdshell
    EXEC sp_configure 'show advanced options', 1;
    RECONFIGURE;
    EXEC sp_configure 'xp_cmdshell', 0;
    RECONFIGURE;

如果系統為SQL Server 2000
可將有安全性考量的SQL SP (shell、regtree、COM+)刪除

use master
EXEC sp_dropextendedproc 'xp_cmdshell'
EXEC sp_dropextendedproc 'Sp_OACreate'
EXEC sp_dropextendedproc 'Sp_OADestroy'
EXEC sp_dropextendedproc 'Sp_OAGetErrorInfo'
EXEC sp_dropextendedproc 'Sp_OAGetProperty'
EXEC sp_dropextendedproc 'Sp_OAMethod'
EXEC sp_dropextendedproc 'Sp_OASetProperty'
EXEC sp_dropextendedproc 'Sp_OAStop'
EXEC sp_dropextendedproc 'Xp_regaddmultistring'
EXEC sp_dropextendedproc 'Xp_regdeletekey'
EXEC sp_dropextendedproc 'Xp_regdeletevalue'
EXEC sp_dropextendedproc 'Xp_regenumvalues'
EXEC sp_dropextendedproc 'Xp_regread'
EXEC sp_dropextendedproc 'Xp_regremovemultistring'
EXEC sp_dropextendedproc 'Xp_regwrite'
drop procedure sp_makewebtask

在 SQL Server 2008 和 SQL Server 2005 中,sp_dropextendedproc 不會卸除系統擴充預存程序。應該由系統管理員拒絕將擴充預存程序的 EXECUTE 權限授與 public 角色。但在 SQL Server 2000 中,您可以使用 sp_dropextendedproc 來卸除任何擴充預存程序。


如果不確定自己是使用什麼SQL Server 版本,可以使用以下語法可以查詢資料庫版本

select @@VERSION


--查詢系統資訊
select * from sys.dm_os_sys_info



4.使用SQL Server Profiler檢視和分析追蹤

當我們想知道誰對SQL Server 做了甚麼事時,就可以使用 SQL Server Profiler 來建立追蹤紀錄,記錄的內容包含所下的SQL語法、Lock狀態、登入的狀況或可用來監視 Database Engine 或 SQL Server Analysis Services 的執行個體....等,可以看到的資訊非常的多,所以您可以擷取每一個事件的相關資料,並將資料儲存至檔案或資料表,以供稍後分析。但也因為這樣SQL Server Profiler使用上多少會影響效能,慎用。

SQL Server Management Studio的「工具」中找到「SQL Server Profiler」



勾選「儲存至檔案」,設定此檔案存放到磁碟C或D
在「設定檔案大小上限(MB)」,輸入 20,表示每個「SQL 追蹤」的檔案大小為 20 MB,每20MB會切割一個檔案。
勾選「啟用檔案換用」
勾選「伺服器處理追蹤資料」
「啟用追蹤停止時間」的意思是,當你開始追蹤後,到所設定的時間系統會自動停止追蹤,這個選項請依實際狀況調整。
點選「執行」


程式執行時,就可以在SQL Profiler中抓到對SQL Server所下達的指令
其中包含「事件類別」、「SQL語法」、「使用者」、「CPU」、「讀取」、「寫入」、「開始時間」與「結束時間」等重要資訊


追蹤結束後到【檔案】->【匯出】 ->【擷取 SQL Server 事件(S) 】->【擷取 Transact-SQL事件(T)】


儲存D:\DBAudit.trc ,就可以先針對敏感的資料表或已知異常語法進行分析與篩選。


5.SQL Server 安全性更新

到Windows 控制台\所有控制台項目\Windows Update\檢視更新記錄
查看是否有更新 SQL Server 2008 Service Pack 3


如果沒有請到下面網址下載
http://support.microsoft.com/kb/2546951/zh-tw

2014年3月12日 星期三

SQL Server 暫時提高權限的做法


我們都知道管理者賦予使用者的權限不要開太高,一般我們會以權限較小的使用者來當啟動帳號但有的時候需要提高權限的時候怎麼辦呢? 方法很簡單我們先來檢查目前的使用者身份

select SUSER_SNAME() 'login name',USER_NAME() 'user name'


確認現在的使用者身份後,就可以來更換使用者帳號了

execute as user='chris'  (chris改為您要提高權限的帳號)



再檢查一次帳號是否變更了

select SUSER_SNAME() 'login name',USER_NAME() 'user name'



如果您要還原原來的身份只要再輸入

revert

就可以了,或是如果你要建立一個預存程序(Store Procedure)但權限不夠也可以加入在語法裡當執行完畢後權限就降回來

create procedure uspuserchange1
with exec as 'sa'
as
begin
select SUSER_SNAME(),USER_NAME()
end
go

2012年1月14日 星期六

SQL SERVER 2008索引維護實作篇

查看索引資訊
我們可以透過指令與親和力的圖形使用者介面進行查看。
(1) 透過 sp_helpindex 儲存程序
clip_image001
(2) 透過 SQL SERVER Management Studio 進行檢索索引資訊
透過物件總管工具,展開目標資料庫->資料表,將會看到索引鍵資料夾
clip_image003clip_image004
建立索引
透過 Create Index 語法來建立索引
CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ] INDEX index_name
ON <object> ( column [ ASC | DESC ] [ ,...n ] )
A. 建立簡單的非叢集索引

   1: USE AdventureWorks;



   2:  



   3: GO



   4:  



   5: IF EXISTS (SELECT name FROM sys.indexes



   6:  



   7: WHERE name = N'IX_ProductVendor_VendorID')



   8:  



   9: DROP INDEX IX_ProductVendor_VendorID ON Purchasing.ProductVendor;



  10:  



  11: GO



  12:  



  13: CREATE INDEX IX_ProductVendor_VendorID 



  14:  



  15: ON Purchasing.ProductVendor (VendorID); 



  16:  



  17: GO




B. 建立簡單的非叢集複合索引




   1: USE AdventureWorks



   2:  



   3: GO



   4:  



   5: IF EXISTS (SELECT name FROM sys.indexes



   6:  



   7: WHERE name = N'IX_SalesPerson_SalesQuota_SalesYTD')



   8:  



   9: DROP INDEX IX_SalesPerson_SalesQuota_SalesYTD ON Sales.SalesPerson ;



  10:  



  11: GO



  12:  



  13: CREATE NONCLUSTERED INDEX IX_SalesPerson_SalesQuota_SalesYTD



  14:  



  15: ON Sales.SalesPerson (SalesQuota, SalesYTD);



  16:  



  17: GO




C. 建立唯一的非叢集索引




   1: USE AdventureWorks;



   2:  



   3: GO



   4:  



   5: IF EXISTS (SELECT name from sys.indexes



   6:  



   7: WHERE name = N'AK_UnitMeasure_Name')



   8:  



   9: DROP INDEX AK_UnitMeasure_Name ON Production.UnitMeasure;



  10:  



  11: GO



  12:  



  13: CREATE UNIQUE INDEX AK_UnitMeasure_Name 



  14:  



  15: ON Production.UnitMeasure(Name);



  16:  



  17: GO




D.建立唯一的叢集所引




   1: USE AdventureWorks;



   2:  



   3: GO



   4:  



   5: IF EXISTS (SELECT name from sys.indexes



   6:  



   7: WHERE name = N'PK_UnitMeasure_ID')



   8:  



   9: DROP INDEX PK_UnitMeasure_ID ON Production.UnitMeasure;



  10:  



  11: GO



  12:  



  13: CREATE UNIQUE CLUSTERED INDEX PK_UnitMeasure_ID 



  14:  



  15: ON Production.UnitMeasure(ID);



  16:  



  17: GO




修改索引


語法:


ALTER INDEX { index_name | ALL } ON <object>


{ REBUILD | DISABLE | REORGANIZE}


A. 重建索引


在 Employee 資料表上,重建單一索引。




   1: USE AdventureWorks;



   2:  



   3: GO



   4:  



   5: ALTER INDEX PK_Employee_EmployeeID ON HumanResources.Employee



   6:  



   7: REBUILD;




GO


B. 在資料表上重新組織索引




   1: USE AdventureWorks;



   2:  



   3: GO



   4:  



   5: ALTER INDEX PK_ProductPhoto_ProductPhotoID ON Production.ProductPhoto



   6:  



   7: REORGANIZE ;




GO


C. 停用索引




   1: USE AdventureWorks;



   2:  



   3: GO



   4:  



   5: ALTER INDEX IX_Employee_ManagerID ON HumanResources.Employee



   6:  



   7: DISABLE ;



   8:  



   9: GO




刪除索引


語法:


DROP INDEX ON 資料表名.索引名 | 檢視表名.索引名


CODE:




   1: DROP INDEX [CustomerID] ON [dbo].[Orders] WITH ( ONLINE = OFF )




使用系統內建的系統資料表查看索引資訊


clip_image006


詳細欄位意義請查詢MSDN官方定義

http://technet.microsoft.com/zh-tw/library/ms190283(SQL.90).aspx


維護索引的統計資訊


索引的統計資訊,可以協助SQL SERVER 的查詢引擎利用這些資訊來確定最佳的查詢計畫,進而提高查詢的效率。





(1) 透過SQL SERVER Management Studio工具進行查看索引統計資訊


依序選擇目標資料庫->資料表->統計資料,如圖示


clip_image008


在要進行查看的索引統計資訊,雙擊滑鼠兩下,將可以看到更詳細的資訊


clip_image010


(2) 透過命令語法


使用系統檢視表sys.stats進行查看


clip_image012


欄位定義請查詢MSDN完整的定義

http://technet.microsoft.com/zh-tw/library/ms177623.aspx


使用DBCC SHOW_STATISTICS 命令


DBCC SHOW_STATISTICS 會針對資料表或索引檢視表顯示目前的查詢最佳化統計資料。


語法




   1: DBCC SHOW_STATISTICS ( table_or_indexed_view_name , target ) 



   2:  



   3: [ WITH [ NO_INFOMSGS ] < option > [ , n ] ]



   4:  



   5: < option > :: =



   6:  



   7: STAT_HEADER | DENSITY_VECTOR | HISTOGRAM | STATS_STREAM




clip_image014


更完整的欄位資訊,請參閱線上MSDN


http://technet.microsoft.com/zh-tw/library/ms174384.aspx


使用系統預存程序 sp_autostats 來查看資料庫中指定的資料表或索引檢視之所有索引和統計資料的自動 UPDATE STATISTICS 設定


clip_image015


(TIP) 在SQL SERVER 2008,資料庫選項的AUTO_CREATE_STATISTICS是最作用於控制是否自動建立索引統計資訊,預設值為ON,因此如果執行了SELECT 、INSERT、UPDATE和DELETE語法中使用到索引指定的欄位,則資料庫會自動為該欄位建立對應的統計資訊,以加速執行查詢計畫。


手動建立索引統計資訊


透過Create Statistics 語法建立





   1: CREATE STATISTICS statistics_name 



   2: ON { table | view } ( column [ ,...n ] ) 



   3: [ WHERE <filter_predicate> ]



   4: [ WITH 



   5: [ [ FULLSCAN 



   6: | SAMPLE number { PERCENT | ROWS } 



   7: | STATS_STREAM = stats_stream ] [ , ] ] 



   8: [ NORECOMPUTE ] 



   9: ] ;




例如,以下為Contact資料表的ContactID, EmailAddress兩個欄位建立統計資訊




   1: CREATE STATISTICS ContactMail1 



   2:  



   3: ON Person.Contact (ContactID, EmailAddress)




使用sp_createstats 預存程序


改程序主要是針對目前資料庫中的所有使用者資料表和內部資料表,建立所有適用資料列的單一資料行統計資料。


語法


sp_createstats [ [ @indexonly = ] 'indexonly' ]


[ , [ @fullscan = ] 'fullscan' ]


[ , [ @norecompute = ] 'norecompute' ]


引數


[ @indexonly = ] 'indexonly'


指定只應考慮建立參與索引之資料行的統計資料。indexonly 是 char(9)。預設值是 NO。


[ @fullscan = ] 'fullscan'


指定搭配 CREATE STATISTICS 來使用 FULLSCAN 選項。如果省略 fullscan,SQL Server Database Engine 會執行預設範例掃描。fullscan 是 char(9)。預設值是 NO。


[ @norecompute = ] 'norecompute'


指定針對新建的統計資料來停用統計資料的自動重新計算。norecompute 是 char(12)。預設值是 NO。


範例是針對目前資料庫中的所有使用者資料表,建立所有適用資料列的統計資料。




   1: EXEC sp_createstats;










修改統計資訊


語法




   1: UPDATE STATISTICS table | view 



   2: [ 



   3: { 



   4: { index | statistics_name }



   5: | ( { index |statistics_name } [ ,...n ] ) 



   6: }



   7: ] 



   8: [ WITH 



   9: [ 



  10: [ FULLSCAN ] 



  11: | SAMPLE number { PERCENT | ROWS } ] 



  12: | RESAMPLE 



  13: ]




此語法結構跟前面講的Create Statistics語法相似,在此直接與取之MSDN範例說明。


A. 更新單一資料表的所有統計資料




   1: UPDATE STATISTICS Sales.SalesOrderDetail;




B. 只更新單一索引的統計資料




   1: UPDATE STATISTICS Sales.SalesOrderDetail AK_SalesOrderDetail_rowguid;




C. 利用 50% 取樣來更新特定統計資料群組 (集合) 的統計資料




   1: CREATE STATISTICS Products



   2:  



   3: ON Production.Product ([Name], ProductNumber)



   4:  



   5: WITH SAMPLE 50 PERCENT



   6:  



   7: -- Time passes. The UPDATE STATISTICS statement is then executed.



   8:  



   9: UPDATE STATISTICS Production.Product(Products) 



  10:  



  11: WITH SAMPLE 50 PERCENT;




D. 利用 FULLSCAN 和 NORECOMPUTE 來更新特定統計資料群組 (集合) 的統計資料




   1: UPDATE STATISTICS Production.Product(Products)



   2:  



   3: WITH FULLSCAN, NORECOMPUTE;




刪除統計資訊


有了前面的基礎,新增、修改統計資訊的觀念後,最後當然也有刪除的語法,刪除很簡單,只要透過簡單的語法 DROP STATISTICS 資料表.索引名,就可以進行刪除。





後續有時間會繼續寫索引如何優化資料庫的觀念………By Allen