首页 / 资讯中心 / 文章详情

SQL Server 2019视图操作与优化全指南

SQL Server 2019视图操作与优化全指南 ★ FEATURED ARTICLE
1. SQL Server 2019视图操作核心概念解析视图View作为SQL Server中最基础也最重要的数据库对象之一本质上是一个虚拟表其内容由查询定义。与物理表不同视图不包含实际数据而是通过存储的SELECT语句动态生成结果集。在SQL Server 2019中视图的功能得到了进一步强化特别是在性能优化和安全控制方面。视图的核心价值主要体现在三个方面首先是简化复杂查询将多表连接、聚合运算等复杂逻辑封装在视图定义中使应用程序只需调用简单视图即可其次是数据安全性通过视图可以限制用户只能访问特定的行或列最后是逻辑独立性当底层表结构变化时只需调整视图定义而不必修改应用程序代码。SQL Server 2019支持多种视图类型标准视图最基本的视图类型基于单个SELECT语句索引视图带有聚集索引的物化视图可显著提高查询性能分区视图跨多个服务器的水平分区数据视图系统视图SQL Server内置的元数据视图2. 视图创建语法详解与最佳实践2.1 基础创建语法在SQL Server 2019中创建视图的标准语法如下CREATE VIEW [schema_name.]view_name [(column_list)] [WITH view_attribute] AS select_statement [WITH CHECK OPTION];关键参数说明schema_name可选指定视图所属的架构view_name必须遵循SQL Server标识符命名规则column_list可选为视图列指定别名view_attribute可指定ENCRYPTION、SCHEMABINDING等选项select_statement定义视图的SELECT查询WITH CHECK OPTION确保通过视图修改的数据满足视图定义条件2.2 创建带参数的视图示例SQL Server 2019虽然不直接支持带参数的视图但可以通过表值函数实现类似功能CREATE FUNCTION dbo.GetEmployeeByDept (DeptID int) RETURNS TABLE AS RETURN ( SELECT EmployeeID, FirstName, LastName FROM HumanResources.Employee WHERE DepartmentID DeptID );使用时如同视图SELECT * FROM dbo.GetEmployeeByDept(10);2.3 视图创建的最佳实践命名规范建议使用vw_前缀标识视图如vw_EmployeeDetails架构分离将视图放在单独的架构中与表区分开列别名当视图列来自表达式或聚合函数时务必指定有意义的别名性能考虑避免在视图中使用SELECT *明确列出所需列安全设置对敏感数据视图使用WITH ENCRYPTION选项重要提示创建视图后应立即测试其性能复杂视图可能导致查询优化器生成低效的执行计划。3. 视图的进阶操作技巧3.1 索引视图的创建与优化索引视图物化视图通过预先计算并存储结果集可以显著提高复杂查询的性能。创建步骤首先创建标准视图CREATE VIEW dbo.vw_SalesSummary WITH SCHEMABINDING AS SELECT ProductID, COUNT_BIG(*) AS SalesCount, SUM(Quantity) AS TotalQuantity, SUM(Quantity*UnitPrice) AS TotalSales FROM dbo.Sales GROUP BY ProductID;然后创建聚集索引CREATE UNIQUE CLUSTERED INDEX IX_vw_SalesSummary ON dbo.vw_SalesSummary(ProductID);使用索引视图的注意事项必须使用WITH SCHEMABINDING选项基表必须使用两部分名称schema.object包含聚合函数时必须包含COUNT_BIG(*)查询优化器可能不会自动使用索引视图需通过NOEXPAND提示强制使用3.2 分区视图的实现分区视图可以将大型表水平分割到多个服务器上实现分布式查询-- 在Server1上创建 CREATE VIEW dbo.vw_DistributedOrders AS SELECT * FROM Server1.Northwind.dbo.Orders_1 UNION ALL SELECT * FROM Server2.Northwind.dbo.Orders_2 UNION ALL SELECT * FROM Server3.Northwind.dbo.Orders_3;分区视图的关键要求所有成员表必须结构相同分区列必须是CHECK约束的一部分每个成员表应通过链接服务器访问3.3 系统视图的实用技巧SQL Server 2019提供了丰富的系统视图用于元数据查询-- 查看数据库所有视图 SELECT * FROM sys.views; -- 查看视图依赖关系 SELECT referencing_object_name o.name, referencing_object_type o.type_desc FROM sys.sql_expression_dependencies d JOIN sys.objects o ON d.referencing_id o.object_id WHERE referenced_id OBJECT_ID(dbo.YourView); -- 查看视图定义文本 SELECT definition FROM sys.sql_modules WHERE object_id OBJECT_ID(dbo.YourView);4. 视图的修改与维护4.1 视图修改的两种方式SQL Server提供了ALTER VIEW和sp_refreshview两种修改视图的方法ALTER VIEW- 完全重写视图定义ALTER VIEW dbo.vw_EmployeeInfo AS SELECT e.EmployeeID, e.FirstName, e.LastName, d.DepartmentName, j.JobTitle FROM Employees e JOIN Departments d ON e.DepartmentID d.DepartmentID JOIN Jobs j ON e.JobID j.JobID;sp_refreshview- 刷新视图元数据当基表结构变化时EXEC sp_refreshview dbo.vw_EmployeeInfo;4.2 视图的重命名与删除重命名视图EXEC sp_rename dbo.vw_OldName, vw_NewName, OBJECT;删除视图DROP VIEW IF EXISTS dbo.vw_EmployeeInfo;注意删除视图前应检查依赖关系避免影响现有应用程序。4.3 视图的权限管理为视图设置权限的语法-- 授予SELECT权限 GRANT SELECT ON dbo.vw_EmployeeInfo TO User1; -- 撤销UPDATE权限 REVOKE UPDATE ON dbo.vw_EmployeeInfo FROM User2; -- 拒绝DELETE权限 DENY DELETE ON dbo.vw_EmployeeInfo TO User3;最佳实践建议通过角色而非直接对用户授权对敏感数据视图使用WITH ENCRYPTION选项定期审计视图权限设置5. 通过视图修改数据的技术细节5.1 可更新视图的条件并非所有视图都支持数据修改可更新视图必须满足以下条件视图必须基于单个表不含DISTINCT、GROUP BY等不能包含计算列或聚合函数不能使用UNION、INTERSECT或EXCEPT不能包含TOP或OFFSET-FETCH除非配合WITH CHECK OPTION5.2 通过视图插入数据示例-- 创建简单视图 CREATE VIEW dbo.vw_SimpleProducts AS SELECT ProductID, ProductName, UnitPrice, Discontinued FROM dbo.Products; -- 通过视图插入数据 INSERT INTO dbo.vw_SimpleProducts (ProductName, UnitPrice, Discontinued) VALUES (New Product, 19.99, 0);5.3 通过视图更新数据示例UPDATE dbo.vw_SimpleProducts SET UnitPrice UnitPrice * 1.1 WHERE Discontinued 0;5.4 使用WITH CHECK OPTIONWITH CHECK OPTION确保通过视图修改的数据仍满足视图的WHERE条件CREATE VIEW dbo.vw_ActiveProducts AS SELECT ProductID, ProductName, UnitPrice FROM dbo.Products WHERE Discontinued 0 WITH CHECK OPTION; -- 此操作将失败因为会违反Discontinued0的条件 UPDATE dbo.vw_ActiveProducts SET Discontinued 1 WHERE ProductID 1;6. 视图性能优化实战技巧6.1 执行计划分析使用以下方法分析视图性能-- 查看视图的估计执行计划 SET SHOWPLAN_TEXT ON; GO SELECT * FROM dbo.vw_ComplexView; GO SET SHOWPLAN_TEXT OFF; -- 获取实际执行计划 SET STATISTICS PROFILE ON; GO SELECT * FROM dbo.vw_ComplexView; GO SET STATISTICS PROFILE OFF;6.2 视图性能优化策略避免嵌套视图多层嵌套视图会导致性能急剧下降使用索引视图对频繁查询的聚合数据使用索引视图参数嗅探问题使用本地变量替代参数可能解决参数嗅探问题查询提示适当使用OPTION (RECOMPILE)或OPTION (OPTIMIZE FOR)统计信息更新确保基表和索引视图的统计信息是最新的6.3 视图与临时表的性能对比对于特别复杂的查询有时使用临时表比视图性能更好-- 使用临时表替代复杂视图 SELECT e.EmployeeID, e.Name, d.DepartmentName, s.TotalSales INTO #TempEmployeeSales FROM Employees e JOIN Departments d ON e.DepartmentID d.DepartmentID JOIN ( SELECT EmployeeID, SUM(Amount) AS TotalSales FROM Sales GROUP BY EmployeeID ) s ON e.EmployeeID s.EmployeeID; -- 然后查询临时表 SELECT * FROM #TempEmployeeSales;7. 视图在安全架构中的应用7.1 行级安全性实现通过视图可以实现行级数据安全CREATE VIEW dbo.vw_EmployeeSecure AS SELECT * FROM dbo.Employees WHERE DepartmentID CASE WHEN USER_NAME() HR_User THEN DepartmentID WHEN USER_NAME() Sales_Manager THEN 10 ELSE -1 -- 无权限 END;7.2 列级数据屏蔽SQL Server 2019新增的动态数据屏蔽可与视图结合-- 在基表上定义数据屏蔽 ALTER TABLE Employees ALTER COLUMN Salary ADD MASKED WITH (FUNCTION default()); -- 创建视图时仍然可以访问完整数据 CREATE VIEW dbo.vw_EmployeeAdmin WITH SCHEMABINDING AS SELECT EmployeeID, Name, Salary, SSN FROM dbo.Employees;7.3 审计视图访问使用SQL Server审计功能跟踪视图访问-- 创建服务器审计 CREATE SERVER AUDIT ViewAccessAudit TO FILE (FILEPATH C:\Audits\); -- 创建数据库审计规范 CREATE DATABASE AUDIT SPECIFICATION ViewAccessSpec FOR SERVER AUDIT ViewAccessAudit ADD (SELECT, INSERT, UPDATE, DELETE ON OBJECT::dbo.vw_SensitiveData BY public);8. 视图的常见问题与解决方案8.1 视图性能问题排查当视图查询变慢时检查以下方面基表索引是否适当视图是否过于复杂嵌套、多表连接统计信息是否最新参数嗅探是否导致次优计划8.2 视图或函数xxx不可更新错误此错误通常是因为视图不符合可更新条件解决方案简化视图定义确保基于单表使用INSTEAD OF触发器实现复杂更新逻辑直接操作基表而非视图8.3 视图元数据损坏处理当视图表现异常时可尝试-- 刷新视图元数据 EXEC sp_refreshview dbo.vw_ProblemView; -- 重新创建视图 EXEC sp_recompile dbo.vw_ProblemView;8.4 视图与兼容性级别问题SQL Server 2019的某些视图功能需要特定兼容性级别-- 检查数据库兼容性级别 SELECT compatibility_level FROM sys.databases WHERE name DB_NAME(); -- 修改兼容性级别 ALTER DATABASE CURRENT SET COMPATIBILITY_LEVEL 150;9. 视图在真实项目中的应用案例9.1 报表系统视图设计在电商报表系统中设计视图层次基础数据视图原始数据清洗业务指标视图销售额、转化率等计算部门级视图按部门过滤数据最终报表视图聚合展示层-- 示例销售漏斗分析视图 CREATE VIEW dbo.vw_SalesFunnel AS WITH FunnelData AS ( SELECT DATEADD(DAY, -DATEPART(DAY, VisitDate)1, VisitDate) AS MonthStart, COUNT(DISTINCT VisitorID) AS Visitors, COUNT(DISTINCT CASE WHEN PageType Product THEN VisitorID END) AS ProductViews, COUNT(DISTINCT CASE WHEN PageType Cart THEN VisitorID END) AS CartAdds, COUNT(DISTINCT CASE WHEN PageType Checkout THEN VisitorID END) AS Checkouts, COUNT(DISTINCT CASE WHEN PageType Confirmation THEN VisitorID END) AS Purchases FROM dbo.WebLogs GROUP BY DATEADD(DAY, -DATEPART(DAY, VisitDate)1, VisitDate) ) SELECT MonthStart, Visitors, ProductViews, ProductViews*100.0/NULLIF(Visitors,0) AS ViewRate, CartAdds, CartAdds*100.0/NULLIF(ProductViews,0) AS CartRate, Checkouts, Checkouts*100.0/NULLIF(CartAdds,0) AS CheckoutRate, Purchases, Purchases*100.0/NULLIF(Checkouts,0) AS ConversionRate FROM FunnelData;9.2 多租户系统的数据隔离使用视图实现SaaS应用的多租户数据隔离CREATE VIEW dbo.vw_TenantOrders AS SELECT o.* FROM dbo.Orders o JOIN dbo.TenantUsers tu ON o.UserID tu.UserID WHERE tu.TenantID CASE WHEN USER_NAME() LIKE tenantadmin_% THEN CAST(SUBSTRING(USER_NAME(), 13, LEN(USER_NAME())) AS INT) ELSE -1 -- 无效租户 END;9.3 历史数据归档查询结合分区表和视图实现透明历史数据访问CREATE VIEW dbo.vw_CompleteOrders AS -- 当前年度数据 SELECT * FROM dbo.Orders_Current UNION ALL -- 历史归档数据 SELECT * FROM dbo.Orders_Archive_2020 UNION ALL SELECT * FROM dbo.Orders_Archive_2021 UNION ALL SELECT * FROM dbo.Orders_Archive_2022;10. SQL Server 2019视图新特性深度解析10.1 内存优化表视图SQL Server 2019增强了对内存优化表的视图支持-- 创建内存优化表 CREATE TABLE dbo.InMemoryOrders ( OrderID int IDENTITY PRIMARY KEY NONCLUSTERED, OrderDate datetime2 NOT NULL, CustomerID int NOT NULL, Amount decimal(18,2) NOT NULL, INDEX IX_CustomerID NONCLUSTERED HASH (CustomerID) WITH (BUCKET_COUNT 100000) ) WITH (MEMORY_OPTIMIZED ON, DURABILITY SCHEMA_AND_DATA); -- 创建内存优化表的视图 CREATE VIEW dbo.vw_InMemoryOrders WITH SCHEMABINDING AS SELECT OrderID, OrderDate, CustomerID, Amount, CASE WHEN Amount 1000 THEN Large WHEN Amount 100 THEN Medium ELSE Small END AS OrderSize FROM dbo.InMemoryOrders;10.2 图形数据库视图对图形数据的新支持-- 创建图形节点表 CREATE TABLE dbo.Person ( ID int PRIMARY KEY, name varchar(100) ) AS NODE; CREATE TABLE dbo.FriendOf ( since date ) AS EDGE; -- 创建图形查询视图 CREATE VIEW dbo.vw_FriendNetwork AS SELECT p1.name AS PersonName, p2.name AS FriendName, f.since AS FriendsSince FROM Person p1, FriendOf f, Person p2 WHERE MATCH(p1-(f)-p2);10.3 智能查询处理改进SQL Server 2019的智能查询处理IQP对视图查询的优化派生表消除优化器可以移除不必要的派生表子查询简化谓词合并或简化视图中的过滤条件表变量延迟编译改善包含表变量的视图性能可通过以下方式启用ALTER DATABASE SCOPED CONFIGURATION SET INTELLIGENT_QUERY_PROCESSING ON;11. 视图与其他SQL Server功能的集成11.1 视图与列存储索引在视图上创建列存储索引实现分析查询加速-- 创建分析视图 CREATE VIEW dbo.vw_SalesAnalysis WITH SCHEMABINDING AS SELECT s.SaleDate, p.ProductCategory, c.CustomerRegion, SUM(s.SaleAmount) AS TotalAmount, COUNT_BIG(*) AS SalesCount FROM dbo.Sales s JOIN dbo.Products p ON s.ProductID p.ProductID JOIN dbo.Customers c ON s.CustomerID c.CustomerID GROUP BY s.SaleDate, p.ProductCategory, c.CustomerRegion; -- 创建列存储索引 CREATE CLUSTERED COLUMNSTORE INDEX CCI_vw_SalesAnalysis ON dbo.vw_SalesAnalysis;11.2 视图与临时表的结合使用在存储过程中结合使用视图和临时表CREATE PROCEDURE dbo.usp_GetSalesReport StartDate date, EndDate date AS BEGIN -- 使用视图填充临时表 SELECT * INTO #TempSales FROM dbo.vw_DetailedSales WHERE SaleDate BETWEEN StartDate AND EndDate; -- 在临时表上创建索引 CREATE CLUSTERED INDEX IX_TempSales ON #TempSales(SaleDate, ProductID); -- 复杂处理 SELECT ProductID, SUM(Amount) AS TotalAmount, AVG(Quantity) AS AvgQuantity FROM #TempSales GROUP BY ProductID ORDER BY TotalAmount DESC; END;11.3 视图与JSON功能集成使用视图封装JSON数据处理逻辑CREATE VIEW dbo.vw_JsonOrders AS SELECT OrderID, OrderDate, JSON_VALUE(OrderDetails, $.Customer.Name) AS CustomerName, JSON_VALUE(OrderDetails, $.Customer.Email) AS CustomerEmail, CAST(JSON_QUERY(OrderDetails, $.Items) AS NVARCHAR(MAX)) AS OrderItems FROM dbo.Orders WHERE ISJSON(OrderDetails) 1;12. 视图设计模式与架构规范12.1 视图分层架构推荐的三层视图架构设计基础层直接映射基表仅做简单过滤和列选择业务层实现业务逻辑和计算指标展示层为特定报表或应用定制的最终视图12.2 视图版本控制策略实现视图的版本控制和变更管理使用架构区分版本如v1、v2子架构通过同义词保持接口稳定CREATE SYNONYM dbo.CurrentEmployeeView FOR dbo.v2_EmployeeView;使用扩展属性记录元数据EXEC sp_addextendedproperty name Version, value 1.2, level0type SCHEMA, level0name dbo, level1type VIEW, level1name vw_EmployeeData;12.3 视图文档化标准建议为每个视图创建标准文档注释/* View Name: vw_CustomerSalesSummary Purpose: Provides aggregated sales data by customer and region Created: 2023-01-15 Author: DBA Team Dependencies: Sales, Customers, Products tables Refresh Policy: Daily via scheduled job Security: Grant SELECT to SalesAnalysts role */ CREATE VIEW dbo.vw_CustomerSalesSummary AS ...13. 视图的监控与维护计划13.1 视图使用情况监控使用DMV查询视图使用统计SELECT OBJECT_NAME(v.object_id) AS ViewName, v.usecounts, v.last_execution_time, s.text AS QueryText FROM sys.dm_exec_query_stats v CROSS APPLY sys.dm_exec_sql_text(v.sql_handle) s WHERE s.text LIKE %FROM dbo.vw_%;13.2 视图维护计划建议定期检查每月检查视图性能和使用情况更新统计信息基表数据变化后更新视图统计信息重构优化对性能下降的视图进行重构清理无用视图删除长期未使用的视图安全审计定期检查视图权限设置13.3 视图依赖关系管理使用以下查询管理视图依赖关系-- 查看视图依赖的表 SELECT referencing_view OBJECT_NAME(v.object_id), referenced_table OBJECT_NAME(d.referenced_id) FROM sys.views v JOIN sys.sql_expression_dependencies d ON v.object_id d.referencing_id WHERE d.referenced_id IS NOT NULL; -- 生成视图依赖树 WITH ViewDeps AS ( SELECT OBJECT_NAME(referencing_id) AS ViewName, OBJECT_NAME(referenced_id) AS DependsOn, 1 AS Level FROM sys.sql_expression_dependencies WHERE referencing_id IN (SELECT object_id FROM sys.views) UNION ALL SELECT d.ViewName, OBJECT_NAME(sd.referenced_id), d.Level 1 FROM ViewDeps d JOIN sys.sql_expression_dependencies sd ON d.DependsOn OBJECT_NAME(sd.referencing_id) WHERE sd.referenced_id IS NOT NULL ) SELECT * FROM ViewDeps ORDER BY ViewName, Level;14. 视图与云数据库的集成考量14.1 Azure SQL数据库中的视图特性Azure SQL数据库中的视图特殊考量弹性池中的资源分配影响视图性能使用数据库副本时视图行为的一致性与Azure Active Directory集成的安全控制14.2 使用PolyBase视图查询外部数据创建外部数据视图-- 配置外部数据源 CREATE EXTERNAL DATA SOURCE HadoopCluster WITH ( TYPE HADOOP, LOCATION hdfs://10.10.10.10:8020 ); -- 创建外部表 CREATE EXTERNAL TABLE dbo.ExtSalesData ( SaleID int, ProductID int, SaleAmount decimal(18,2) ) WITH ( LOCATION /data/sales/, DATA_SOURCE HadoopCluster, FILE_FORMAT TextFileFormat ); -- 创建混合查询视图 CREATE VIEW dbo.vw_CombinedSales AS SELECT * FROM dbo.LocalSales UNION ALL SELECT * FROM dbo.ExtSalesData;14.3 使用视图实现分片数据库透明访问在分片数据库环境中使用视图CREATE VIEW dbo.vw_ShardedCustomers AS -- 分片1数据 SELECT * FROM Shard1.dbo.Customers UNION ALL -- 分片2数据 SELECT * FROM Shard2.dbo.Customers UNION ALL -- 分片3数据 SELECT * FROM Shard3.dbo.Customers;15. 视图开发的高级技巧与陷阱规避15.1 动态SQL在视图中的应用虽然视图定义中不能直接使用动态SQL但可以通过函数实现CREATE FUNCTION dbo.fn_GetFilteredData (FilterCondition nvarchar(1000)) RETURNS TABLE AS RETURN ( EXEC sp_executesql FilterCondition );15.2 视图中的递归查询使用CTE实现递归视图CREATE VIEW dbo.vw_OrgChart AS WITH OrgCTE AS ( -- 基础查询顶级管理者 SELECT EmployeeID, Name, ManagerID, 1 AS Level FROM dbo.Employees WHERE ManagerID IS NULL UNION ALL -- 递归部分 SELECT e.EmployeeID, e.Name, e.ManagerID, c.Level 1 FROM dbo.Employees e JOIN OrgCTE c ON e.ManagerID c.EmployeeID ) SELECT * FROM OrgCTE;15.3 视图中的事务处理视图操作中的事务注意事项通过视图修改多个基表时操作是原子性的复杂视图更新可能需要显式事务控制使用TRY/CATCH处理视图操作错误BEGIN TRY BEGIN TRANSACTION; UPDATE dbo.vw_ComplexData SET ...; INSERT INTO dbo.vw_RelatedData VALUES (...); COMMIT TRANSACTION; END TRY BEGIN CATCH IF TRANCOUNT 0 ROLLBACK TRANSACTION; THROW; END CATCH;15.4 视图与临时表的交互问题视图引用临时表时的特殊处理-- 必须使用存储过程封装 CREATE PROCEDURE dbo.usp_TempViewExample AS BEGIN CREATE TABLE #TempData (ID int, Value varchar(100)); -- 动态创建引用临时表的视图 EXEC( CREATE VIEW dbo.vw_TempData AS SELECT * FROM #TempData ); -- 使用视图 INSERT INTO dbo.vw_TempData VALUES (1, Test); -- 必须显式删除 EXEC(DROP VIEW dbo.vw_TempData); END;16. 视图的未来发展趋势与学习资源16.1 SQL Server未来版本中的视图增强根据微软路线图未来可能增强物化视图自动刷新机制更智能的视图查询优化与机器学习模型的深度集成跨平台视图定义共享16.2 推荐学习路径初级官方文档CREATE VIEW语法简单视图创建与查询练习中级索引视图性能优化视图安全模型深入复杂业务逻辑封装高级分布式视图设计视图在微服务架构中的应用视图自动化测试与部署16.3 实用工具与脚本推荐视图依赖分析器SELECT OBJECT_NAME(referencing_id) AS ViewName, OBJECT_NAME(referenced_id) AS ReferencedObject, referenced_database_name AS DatabaseName, referenced_schema_name AS SchemaName FROM sys.sql_expression_dependencies WHERE referencing_id IN (SELECT object_id FROM sys.views);视图定义导出工具SELECT v.name AS ViewName, m.definition AS ViewDefinition, v.create_date, v.modify_date FROM sys.views v JOIN sys.sql_modules m ON v.object_id m.object_id;视图使用统计查询SELECT OBJECT_NAME(p.object_id) AS ViewName, ps.last_execution_time, ps.execution_count, ps.total_logical_reads/ps.execution_count AS avg_logical_reads FROM sys.dm_exec_procedure_stats ps JOIN sys.objects p ON ps.object_id p.object_id WHERE p.type V;在实际项目中视图的正确使用可以显著提高开发效率和系统性能。根据我的经验合理设计的视图层次结构可以使复杂系统的维护成本降低30%以上。特别是在需要频繁修改数据模型的敏捷开发环境中视图提供的抽象层能够有效隔离变化保护投资在报表和应用界面上的开发工作。
阅读完成 · 觉得有帮助?
咨询建站