最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#中SQL Server數(shù)據(jù)庫(kù)調(diào)優(yōu)的基礎(chǔ)方法

 更新時(shí)間:2025年12月02日 08:59:45   作者:周杰倫fans  
本文介紹了C#中SQL Server數(shù)據(jù)庫(kù)調(diào)優(yōu)的基礎(chǔ)方法,調(diào)優(yōu)旨在提升數(shù)據(jù)庫(kù)查詢(xún)性能,解決常見(jiàn)的性能問(wèn)題,通過(guò)對(duì)比反面示例,展示了N+1查詢(xún)問(wèn)題和SQL注入風(fēng)險(xiǎn),需要的朋友可以參考下

1. 什么是數(shù)據(jù)庫(kù)調(diào)優(yōu)?

想象一下,數(shù)據(jù)庫(kù)就像一個(gè)大圖書(shū)館,調(diào)優(yōu)就是讓圖書(shū)管理員(數(shù)據(jù)庫(kù))更快地找到你要的書(shū)(數(shù)據(jù))。

簡(jiǎn)單說(shuō):數(shù)據(jù)庫(kù)調(diào)優(yōu)就是讓數(shù)據(jù)庫(kù)運(yùn)行得更快、更穩(wěn)定!

2. 為什么要調(diào)優(yōu)?

先看一個(gè)反面例子(不好的代碼):

// ? 糟糕的寫(xiě)法 - 性能很差
public List<User> GetUserOrders(int userId)
{
    var users = new List<User>();
    
    using (var connection = new SqlConnection(connectionString))
    {
        connection.Open();
        
        // 問(wèn)題1:在循環(huán)中執(zhí)行SQL查詢(xún)(N+1問(wèn)題)
        var userSql = "SELECT * FROM Users WHERE IsActive = 1";
        using (var userCommand = new SqlCommand(userSql, connection))
        {
            using (var reader = userCommand.ExecuteReader())
            {
                while (reader.Read())
                {
                    var user = new User 
                    {
                        Id = (int)reader["Id"],
                        Name = (string)reader["Name"]
                    };
                    
                    // 問(wèn)題2:為每個(gè)用戶(hù)單獨(dú)查詢(xún)訂單
                    var orderSql = $"SELECT * FROM Orders WHERE UserId = {user.Id}";
                    using (var orderCommand = new SqlCommand(orderSql, connection))
                    {
                        using (var orderReader = orderCommand.ExecuteReader())
                        {
                            while (orderReader.Read())
                            {
                                user.Orders.Add(new Order 
                                {
                                    Id = (int)orderReader["Id"],
                                    Amount = (decimal)orderReader["Amount"]
                                });
                            }
                        }
                    }
                    
                    users.Add(user);
                }
            }
        }
    }
    
    return users;
}

3. C# 代碼層面的調(diào)優(yōu)技巧

技巧1:使用參數(shù)化查詢(xún)(防止SQL注入+性能提升)

// ? 好的寫(xiě)法
public User GetUserById(int userId)
{
    using (var connection = new SqlConnection(connectionString))
    {
        connection.Open();
        
        // 使用參數(shù)化查詢(xún)
        var sql = "SELECT Id, Name, Email FROM Users WHERE Id = @UserId AND IsActive = 1";
        
        using (var command = new SqlCommand(sql, connection))
        {
            // 添加參數(shù)
            command.Parameters.AddWithValue("@UserId", userId);
            
            using (var reader = command.ExecuteReader())
            {
                if (reader.Read())
                {
                    return new User 
                    {
                        Id = (int)reader["Id"],
                        Name = (string)reader["Name"],
                        Email = (string)reader["Email"]
                    };
                }
            }
        }
    }
    
    return null;
}

技巧2:一次性獲取數(shù)據(jù)(解決N+1問(wèn)題)

// ? 好的寫(xiě)法 - 使用 JOIN 一次性獲取數(shù)據(jù)
public List<User> GetUsersWithOrders()
{
    var users = new List<User>();
    
    using (var connection = new SqlConnection(connectionString))
    {
        connection.Open();
        
        // 使用 JOIN 一次性獲取用戶(hù)和訂單數(shù)據(jù)
        var sql = @"
            SELECT u.Id, u.Name, o.Id as OrderId, o.Amount, o.OrderDate
            FROM Users u
            LEFT JOIN Orders o ON u.Id = o.UserId
            WHERE u.IsActive = 1
            ORDER BY u.Id, o.OrderDate DESC";
        
        using (var command = new SqlCommand(sql, connection))
        {
            using (var reader = command.ExecuteReader())
            {
                User currentUser = null;
                
                while (reader.Read())
                {
                    int userId = (int)reader["Id"];
                    
                    // 如果是新用戶(hù),創(chuàng)建用戶(hù)對(duì)象
                    if (currentUser == null || currentUser.Id != userId)
                    {
                        currentUser = new User 
                        {
                            Id = userId,
                            Name = (string)reader["Name"],
                            Orders = new List<Order>()
                        };
                        users.Add(currentUser);
                    }
                    
                    // 添加訂單(如果有)
                    if (!reader.IsDBNull(reader.GetOrdinal("OrderId")))
                    {
                        currentUser.Orders.Add(new Order 
                        {
                            Id = (int)reader["OrderId"],
                            Amount = (decimal)reader["Amount"],
                            OrderDate = (DateTime)reader["OrderDate"]
                        });
                    }
                }
            }
        }
    }
    
    return users;
}

技巧3:合理使用連接池

// ? 好的寫(xiě)法 - 連接字符串中啟用連接池
// 在配置文件中:
// "Server=.;Database=MyDB;Integrated Security=true;Max Pool Size=100;Min Pool Size=10;"

public class UserRepository
{
    private readonly string _connectionString;
    
    public UserRepository(string connectionString)
    {
        _connectionString = connectionString;
    }
    
    public async Task<User> GetUserAsync(int userId)
    {
        // .NET 會(huì)自動(dòng)管理連接池
        using (var connection = new SqlConnection(_connectionString))
        {
            await connection.OpenAsync();
            
            var sql = "SELECT * FROM Users WHERE Id = @UserId";
            using (var command = new SqlCommand(sql, connection))
            {
                command.Parameters.AddWithValue("@UserId", userId);
                
                using (var reader = await command.ExecuteReaderAsync())
                {
                    if (await reader.ReadAsync())
                    {
                        return new User 
                        {
                            Id = reader.GetInt32("Id"),
                            Name = reader.GetString("Name")
                        };
                    }
                }
            }
        }
        
        return null;
    }
}

4. SQL Server 層面的調(diào)優(yōu)

技巧4:創(chuàng)建合適的索引

// 在C#中執(zhí)行創(chuàng)建索引的SQL(通常在數(shù)據(jù)庫(kù)遷移中執(zhí)行)
public async Task CreateIndexesAsync()
{
    using (var connection = new SqlConnection(connectionString))
    {
        await connection.OpenAsync();
        
        // 為經(jīng)常查詢(xún)的字段創(chuàng)建索引
        var createIndexSql = @"
            -- 為用戶(hù)表的常用查詢(xún)字段創(chuàng)建索引
            CREATE INDEX IX_Users_Email ON Users(Email);
            CREATE INDEX IX_Users_IsActive ON Users(IsActive);
            CREATE INDEX IX_Orders_UserId_OrderDate ON Orders(UserId, OrderDate DESC);
            
            -- 為訂單表的查詢(xún)字段創(chuàng)建索引
            CREATE INDEX IX_Orders_OrderDate ON Orders(OrderDate);
            CREATE INDEX IX_Orders_Status ON Orders(Status);";
        
        using (var command = new SqlCommand(createIndexSql, connection))
        {
            await command.ExecuteNonQueryAsync();
        }
    }
}

技巧5:分頁(yè)查詢(xún)(避免一次性獲取大量數(shù)據(jù))

// ? 好的寫(xiě)法 - 分頁(yè)查詢(xún)
public async Task<List<User>> GetUsersPagedAsync(int pageNumber, int pageSize)
{
    var users = new List<User>();
    
    using (var connection = new SqlConnection(connectionString))
    {
        await connection.OpenAsync();
        
        // 使用 OFFSET/FETCH 進(jìn)行分頁(yè)(SQL Server 2012+)
        var sql = @"
            SELECT Id, Name, Email, CreatedDate
            FROM Users
            WHERE IsActive = 1
            ORDER BY CreatedDate DESC
            OFFSET @Offset ROWS
            FETCH NEXT @PageSize ROWS ONLY";
        
        using (var command = new SqlCommand(sql, connection))
        {
            command.Parameters.AddWithValue("@Offset", (pageNumber - 1) * pageSize);
            command.Parameters.AddWithValue("@PageSize", pageSize);
            
            using (var reader = await command.ExecuteReaderAsync())
            {
                while (await reader.ReadAsync())
                {
                    users.Add(new User 
                    {
                        Id = reader.GetInt32("Id"),
                        Name = reader.GetString("Name"),
                        Email = reader.GetString("Email"),
                        CreatedDate = reader.GetDateTime("CreatedDate")
                    });
                }
            }
        }
    }
    
    return users;
}

5. 使用 Entity Framework 的調(diào)優(yōu)技巧

技巧6:EF Core 性能優(yōu)化

// ? 好的寫(xiě)法 - 使用 EF Core 的優(yōu)化技巧
public class UserService
{
    private readonly MyDbContext _context;
    
    public UserService(MyDbContext context)
    {
        _context = context;
    }
    
    // 只查詢(xún)需要的字段(不要 SELECT *)
    public async Task<List<UserDto>> GetActiveUsersAsync()
    {
        return await _context.Users
            .Where(u => u.IsActive)
            .Select(u => new UserDto  // 使用DTO,不要返回整個(gè)實(shí)體
            {
                Id = u.Id,
                Name = u.Name,
                Email = u.Email
            })
            .AsNoTracking()  // 只讀操作使用 AsNoTracking
            .ToListAsync();
    }
    
    // 使用 Include 一次性加載關(guān)聯(lián)數(shù)據(jù)
    public async Task<List<User>> GetUsersWithOrdersAsync()
    {
        return await _context.Users
            .Where(u => u.IsActive)
            .Include(u => u.Orders)  // 一次性加載訂單
            .ThenInclude(o => o.OrderDetails)  // 加載訂單詳情
            .AsNoTracking()
            .ToListAsync();
    }
    
    // 分頁(yè)查詢(xún)
    public async Task<PagedResult<UserDto>> GetUsersPagedAsync(int page, int pageSize)
    {
        var query = _context.Users
            .Where(u => u.IsActive)
            .OrderBy(u => u.Name);
            
        var totalCount = await query.CountAsync();
        var items = await query
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .Select(u => new UserDto
            {
                Id = u.Id,
                Name = u.Name,
                Email = u.Email
            })
            .AsNoTracking()
            .ToListAsync();
            
        return new PagedResult<UserDto>(items, totalCount, page, pageSize);
    }
}

6. 監(jiān)控和診斷

技巧7:添加性能監(jiān)控

public class MonitoringUserRepository
{
    private readonly ILogger<MonitoringUserRepository> _logger;
    
    public MonitoringUserRepository(ILogger<MonitoringUserRepository> logger)
    {
        _logger = logger;
    }
    
    public async Task<User> GetUserWithMonitoringAsync(int userId)
    {
        var stopwatch = Stopwatch.StartNew();
        
        try
        {
            using (var connection = new SqlConnection(connectionString))
            {
                await connection.OpenAsync();
                
                var sql = "SELECT * FROM Users WHERE Id = @UserId";
                using (var command = new SqlCommand(sql, connection))
                {
                    command.Parameters.AddWithValue("@UserId", userId);
                    
                    using (var reader = await command.ExecuteReaderAsync())
                    {
                        if (await reader.ReadAsync())
                        {
                            return new User 
                            {
                                Id = reader.GetInt32("Id"),
                                Name = reader.GetString("Name")
                            };
                        }
                    }
                }
            }
            
            return null;
        }
        finally
        {
            stopwatch.Stop();
            _logger.LogInformation("數(shù)據(jù)庫(kù)查詢(xún)耗時(shí): {ElapsedMilliseconds}ms", stopwatch.ElapsedMilliseconds);
            
            // 如果查詢(xún)時(shí)間超過(guò)閾值,記錄警告
            if (stopwatch.ElapsedMilliseconds > 1000)
            {
                _logger.LogWarning("慢查詢(xún)警告: 獲取用戶(hù) {UserId} 耗時(shí) {ElapsedMilliseconds}ms", 
                    userId, stopwatch.ElapsedMilliseconds);
            }
        }
    }
}

7. 調(diào)優(yōu)檢查清單

給小白同學(xué)的簡(jiǎn)單檢查清單

? C#代碼層面:

  • 使用參數(shù)化查詢(xún)(不要拼接SQL字符串)
  • 一次性獲取數(shù)據(jù)(避免N+1查詢(xún)問(wèn)題)
  • 使用分頁(yè)(不要一次性獲取大量數(shù)據(jù))
  • 及時(shí)關(guān)閉數(shù)據(jù)庫(kù)連接(使用using語(yǔ)句)

? SQL Server層面:

  • 為經(jīng)常查詢(xún)的字段創(chuàng)建索引
  • 避免 SELECT *,只查詢(xún)需要的字段
  • 大數(shù)據(jù)表使用分頁(yè)
  • 定期維護(hù)數(shù)據(jù)庫(kù)(更新統(tǒng)計(jì)信息等)

? 架構(gòu)層面:

  • 使用緩存(Redis等)減少數(shù)據(jù)庫(kù)壓力
  • 讀寫(xiě)分離(查詢(xún)用從庫(kù),寫(xiě)入用主庫(kù))
  • 考慮使用NoSQL處理非關(guān)系型數(shù)據(jù)

總結(jié)

數(shù)據(jù)庫(kù)調(diào)優(yōu)就像開(kāi)車(chē)時(shí)保養(yǎng)車(chē)輛

  • 好的代碼 = 良好的駕駛習(xí)慣
  • 索引 = 給車(chē)輛加好機(jī)油
  • 連接池 = 合理的加油站選擇
  • 監(jiān)控 = 車(chē)輛的儀表盤(pán)

記住:調(diào)優(yōu)是一個(gè)持續(xù)的過(guò)程,不是一次性的任務(wù)。先從最簡(jiǎn)單的優(yōu)化開(kāi)始,逐步深入!

到此這篇關(guān)于C#中SQL Server數(shù)據(jù)庫(kù)調(diào)優(yōu)的基礎(chǔ)方法的文章就介紹到這了,更多相關(guān)C# SQL Server調(diào)優(yōu)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#中委托和事件的區(qū)別詳解

    C#中委托和事件的區(qū)別詳解

    C# 中的委托(Delegate)類(lèi)似于 C 或 C++ 中函數(shù)的指針。事件是在委托類(lèi)型變量前加上 event 關(guān)鍵字,其本質(zhì)是用來(lái)對(duì)委托類(lèi)型的變量進(jìn)行封裝,類(lèi)似于類(lèi)的屬性對(duì)字段的封裝。本文就來(lái)聊聊C#中委托和事件的區(qū)別,感興趣的可以了解一下
    2022-11-11
  • C#使用Lambda表達(dá)式簡(jiǎn)化代碼的示例詳解

    C#使用Lambda表達(dá)式簡(jiǎn)化代碼的示例詳解

    Lambda,希臘字母λ,在C#編程語(yǔ)言中,被引入為L(zhǎng)ambda表達(dá)式,表示為匿名函數(shù)(匿名方法)。本文將利用Lambda表達(dá)式進(jìn)行代碼的簡(jiǎn)化,感興趣的可以了解一下
    2022-12-12
  • C#?Timer控件學(xué)習(xí)之使用Timer解決按鈕冪等性問(wèn)題

    C#?Timer控件學(xué)習(xí)之使用Timer解決按鈕冪等性問(wèn)題

    Timer控件又稱(chēng)定時(shí)器控件或計(jì)時(shí)器控件,該控件的主要作用是按一定的時(shí)間間隔周期性地觸發(fā)一個(gè)名為T(mén)ick的事件,因此在該事件的代碼中可以放置一些需要每隔一段時(shí)間重復(fù)執(zhí)行的程序段,這篇文章主要介紹了關(guān)于C#使用Timer解決按鈕冪等性問(wèn)題的相關(guān)資料,需要的朋友可以參考下
    2022-10-10
  • C# Nullable的使用小結(jié)

    C# Nullable的使用小結(jié)

    本文主要介紹了C# Nullable的使用小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • C#使用ODBC與OLEDB連接數(shù)據(jù)庫(kù)的方法示例

    C#使用ODBC與OLEDB連接數(shù)據(jù)庫(kù)的方法示例

    這篇文章主要介紹了C#使用ODBC與OLEDB連接數(shù)據(jù)庫(kù)的方法,結(jié)合實(shí)例形式分析了C#基于ODBC與OLEDB實(shí)現(xiàn)數(shù)據(jù)庫(kù)連接操作簡(jiǎn)單操作技巧,需要的朋友可以參考下
    2017-05-05
  • 詳解WPF中值轉(zhuǎn)換器的使用方法

    詳解WPF中值轉(zhuǎn)換器的使用方法

    在WPF(Windows Presentation Foundation)中,值轉(zhuǎn)換器(Value Converter)是一種機(jī)制,允許你在綁定時(shí)轉(zhuǎn)換綁定源和綁定目標(biāo)之間的值,本文給大家介紹了WPF中值轉(zhuǎn)換器的使用方法,需要的朋友可以參考下
    2024-02-02
  • 如何利用C#正則表達(dá)式判斷是否是有效的文件及文件夾路徑

    如何利用C#正則表達(dá)式判斷是否是有效的文件及文件夾路徑

    項(xiàng)目中少不了讀取或設(shè)置文件路徑的功能,如何才能對(duì)輸入的路徑是否合法進(jìn)行判斷呢?下面這篇文章主要給大家介紹了關(guān)于C#利用正則表達(dá)式判斷是否是有效的文件及文件夾路徑的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • C#函數(shù)式編程中的遞歸調(diào)用之尾遞歸詳解

    C#函數(shù)式編程中的遞歸調(diào)用之尾遞歸詳解

    這篇文章主要介紹了C#函數(shù)式編程中的遞歸調(diào)用詳解,本文講解了什么是尾遞歸、尾遞歸的多種方式、尾遞歸的代碼實(shí)例等內(nèi)容,需要的朋友可以參考下
    2015-01-01
  • C#去除字符串中的反斜杠實(shí)例(推薦)

    C#去除字符串中的反斜杠實(shí)例(推薦)

    下面小編就為大家分享一篇C#去除字符串中的反斜杠實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • C#通過(guò)KD樹(shù)進(jìn)行距離最近點(diǎn)的查找

    C#通過(guò)KD樹(shù)進(jìn)行距離最近點(diǎn)的查找

    這篇文章主要為大家詳細(xì)介紹了C#通過(guò)KD樹(shù)進(jìn)行距離最近點(diǎn)的查找,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09

最新評(píng)論

上高县| 修水县| 鹤山市| 辛集市| 静海县| 达拉特旗| 进贤县| 客服| 漾濞| 张家口市| 交口县| 龙川县| 平邑县| 庆城县| 诸暨市| 驻马店市| 鄂尔多斯市| 且末县| 葵青区| 铜山县| 郓城县| 安庆市| 蓝山县| 衡南县| 资溪县| 同仁县| 广宁县| 沂南县| 沁水县| 呼和浩特市| 临泽县| 大渡口区| 明光市| 沁阳市| 阿拉善右旗| 奉新县| 台山市| 西盟| 海南省| 海宁市| 襄樊市|