


















自增列作为主键可以简化数据的插入操作,避免因插入非顺序的主键值导致的索引分裂和碎片化,从而提高数据库性能。自增列也易于分配和管理,且不会与其他记录的主键冲突。
触发器是一种特殊的存储过程,它在特定数据库操作(如INSERT、UPDATE、DELETE)执行之前或之后自动触发执行。触发器可以用于维护数据完整性、实施复杂的业务规则、自动更新表中的数据等。
存储过程是一组为了执行特定任务而预编译的SQL语句。它们可以提高性能,因为只需编译一次,之后可以重复调用。存储过程可以通过SQL命令直接调用,也可以被应用程序通过特定的API调用来执行。
存储过程的优点包括提高性能(预编译)、减少网络传输、增强安全性(需要特定权限才能执行)、便于代码复用。缺点包括移植性差,因为它们通常与特定的数据库系统紧密相关。
存储过程是一系列为了完成特定功能的SQL语句集合,可以通过参数传递数据,并且可以有多个返回值。函数通常返回一个单一的数据值,并且在使用时作为表达式的一部分。存储过程使用更灵活,而函数则更适用于需要返回特定数据结构的场景。
视图是基于SQL查询的虚拟表,它像实际的表一样可以进行查询和更新操作,但是不存储数据,而是在查询视图时动态生成结果。游标是一种数据库对象,用于逐行处理查询结果集,常用于需要对结果集进行循环处理的场景。
视图的优点包括简化复杂的查询、提高数据安全性、实现数据逻辑抽象。缺点包括可能影响性能(尤其是在复杂的视图上执行查询时),以及在某些情况下限制了数据的更新操作。
临时表是在当前会话或事务中创建的表,仅对当前会话可见。当会话结束或事务提交时,临时表及其数据会自动删除。
非关系型数据库(NoSQL)和关系型数据库在数据模型、查询方式、扩展性等方面有本质区别。非关系型数据库通常提供更高的扩展性和灵活性,适合处理大规模分布式数据。关系型数据库则在数据一致性、复杂查询和事务管理方面表现更好。
数据库范式是一套用于指导数据库设计的规范,包括第一范式(1NF)、第二范式(2NF)、第三范式(3NF)等,目的是减少数据冗余和提高数据完整性。设计数据表时,应根据业务需求和数据关系来确定表结构,确保满足相应的范式要求。
内连接只返回两个表中匹配的行;外连接(左外连接、右外连接)会返回一个表的全部行,另一个表中匹配的行,不匹配的行用NULL填充;交叉连接返回两个表的笛卡尔积,即每行与另一个表中每行的组合;笛卡尔积是两个集合所有可能的组合。
VARCHAR适用于长度可变的数据,如用户输入的评论或描述,因为它可以根据实际内容长度存储,节省空间。CHAR适用于长度固定的数据,如性别或国家代码,因为它可以提供更快的存取速度,但会使用固定长度的存储空间。
SQL语言主要分为数据查询语言(DQL),数据操纵语言(DML),数据定义语言(DDL)和数据控制语言(DCL)。DQL用于查询数据,如SELECT;DML用于数据的增删改,如INSERT、UPDATE、DELETE;DDL用于数据库对象的定义,如CREATE、ALTER、DROP;DCL用于控制数据库访问权限,如GRANT、REVOKE。
LIKE '%xxx%'表示匹配包含xxx的任意字符串,无论xxx出现在哪一部分。LIKE 'xxx%'表示匹配以xxx结尾的字符串。两者在模糊匹配时使用不同的通配符,%代表任意字符出现任意次数,而_仅代表单个字符。
COUNT()用于计算表中的总行数,包括NULL值。COUNT(1)是COUNT()的等价操作,用于计算行数。COUNT(column)用于计算特定列中非NULL值的数量。
最左前缀原则是索引创建和使用的一个重要原则,它指的是在多列索引中,数据库查询优化器只会使用索引的最左部分列。这意味着如果查询条件没有使用到索引的第一个列,那么即使后面的列被使用到,索引也可能不会被利用。
索引的作用是加快数据检索速度,排序和分组数据,以及保证数据的唯一性。优点包括提高查询速度、加速表连接、支持数据的排序和分组。缺点包括增加存储空间、降低数据更新(INSERT、UPDATE、DELETE)的速度,以及维护索引本身需要额外的开销。
适合建索引的字段包括经常需要搜索的列、作为主键的列、经常用于连接的列、经常需要进行范围搜索的列、经常需要排序的列,以及经常使用在WHERE子句中的列。
聚集索引决定了表中数据的物理存储顺序,使得相关列的数据在物理上连续存放,查询效率较高,但修改数据时可能较慢。非聚集索引指定了表中数据的逻辑顺序,但物理存储顺序与索引可能不一致,通常用于频繁更新的数据列。
SQL注入式攻击是一种网络安全攻击手段,攻击者通过在Web表单输入域或页面请求的查询字符串中插入恶意SQL命令,欺骗服务器执行这些命令,从而获取、篡改或删除数据库中的数据。
防范SQL注入式攻击的方法包括:对用户输入进行过滤和验证,替换或转义特殊字符;使用预处理语句(参数化查询);限制数据库权限,使用最小权限原则;使用存储过程;以及在服务器端进行输入验证等。
内存泄漏是指在程序运行过程中,由于未能适当释放不再使用的内存,导致随着程序的持续运行,可用内存逐渐减少的现象。在动态内存分配的语言中,如C或C++,如果使用new分配了内存,却忘记使用delete释放,就可能发生内存泄漏。
维护数据库的完整性和一致性,通常首选使用数据库提供的约束,如CHECK、PRIMARY KEY、FOREIGN KEY等。其次是使用触发器,因为它们可以自动执行,确保数据的完整性和一致性,无论哪种业务逻辑访问数据库。最后考虑自写业务逻辑,但这种方法编程复杂,效率较低。
事务是一系列操作,它们作为一个整体被执行,以确保数据的完整性。如果事务中的任何操作失败,整个事务将回滚到执行前的状态。锁是数据库管理系统用来保证事务的隔离性和并发控制的一种机制,它可以防止多个事务同时修改同一数据,从而避免数据冲突。
过多的索引虽然可以提高查询速度,但在数据的插入、更新和删除操作时,数据库引擎需要更多的时间来维护这些索引,这可能会导致性能下降。因此,需要在索引创建时进行权衡,以确保数据库操作的整体性能。
相关子查询是一种特殊类型的子查询,它在查询中使用外部查询的值。这种子查询通常用于WHERE或HAVING子句中,可以基于外部查询的结果来动态地定义查询条件。
TempDB是SQL Server的一个系统数据库,用于存储临时数据,如临时表和表变量。许多操作,包括创建表时的临时数据、执行某些类型的JOIN操作、使用游标以及存储过程和批处理中的一些操作,都可能会用到TempDB。
TempDB异常变大可能是由于大量使用临时表或返回的记录集过大造成的。处理方法包括优化查询以减少返回的数据量,使用分批处理,或者调整TempDB的大小和配置。
索引类型主要包括聚集索引和非聚集索引。聚集索引决定了表中数据的物理存储顺序,非聚集索引则不改变数据的物理存储顺序。索引的优点包括提高查询速度、确保数据的唯一性和排序。缺点是增加了存储空间和维护成本,降低了数据更新的速度。
Job信息可以通过SQL Server的msdb数据库中的表,如sysjobs和sysjobhistory获取。系统正在运行的语句可以通过动态管理视图如sys.dm_exec_requests获取。要获取某个T-SQL语句的IO和Time等信息,可以使用SQL Server Profiler或相关的动态管理视图。
确保字段只接受特定范围内的值
可以通过在字段上设置CHECK约束来确保只接受特定范围内的值。CHECK约束允许定义字段值的范围或条件,确保插入或更新数据时满足这些条件。
n 个字节的存储空间。适合存储长度相对固定的数据(如身份证号、电话号码)。n,表示最多可存储 n 个字符(无论中英文)。核心区别: CHAR/VARCHAR 用于非 Unicode,一个英文字符占1字节,一个中文字符可能占2字节(取决于编码)。NCHAR/NVARCHAR 用于 Unicode,任何字符都占2字节,能全球通用。
| 特性 | DELETE | TRUNCATE | DROP |
|---|---|---|---|
| 类型 | DML(数据操作语言) | DDL(数据定义语言) | DDL(数据定义语言) |
| 条件 | 可以带 WHERE 子句 | 不能带条件,清空所有数据 | 删除整个表(结构和数据) |
| 事务 | 操作会被记录在事务日志中,可回滚 | 操作记录最少,不可回滚 | 操作不可回滚 |
| 触发器 | 会触发 DELETE 触发器 | 不会触发触发器 | - |
| 标识列 | 不影响标识列的当前值 | 重置标识列的种子值 | - |
| 性能 | 较慢(逐行删除并记录日志) | 非常快(直接释放数据页) | 快 |
| 锁 | 行级锁 | 表锁 | 表锁 |
Ctrl + M(显示实际执行计划)或 Ctrl + L(显示估计执行计划),然后执行查询。SET SHOWPLAN_TEXT ON 或 SET STATISTICS PROFILE ON。一个覆盖索引是指一个非聚集索引,它包含了查询中需要的所有字段。当查询的所有列都包含在索引的键或包含列中时,引擎可以直接从索引页中获取数据,而无需再去查找数据页,从而避免昂贵的键查找操作,极大提升性能。
创建覆盖索引示例:
CREATE INDEX IX_Covering ON Orders (CustomerID) INCLUDE (OrderDate, TotalAmount);
-- 对于查询: SELECT OrderDate, TotalAmount FROM Orders WHERE CustomerID = @ID
-- 这个索引就是覆盖索引。
名词解释:
LOCK_TIMEOUT 设置。这是基于快照隔离级别的机制。当数据被修改时,SQL Server 会在 TempDB 中保存被修改行的旧版本。其他正在读取的事务可以从 TempDB 中读取这个旧版本,从而不会与写事务发生阻塞。READ_COMMITTED_SNAPSHOT 和 ALLOW_SNAPSHOT_ISOLATION 数据库选项与此相关。
FOR JSON PATH/AUTO, OPENJSON 等。| 特性 | 存储过程 | 函数 |
|---|---|---|
| 返回值 | 可以没有返回值,或通过 OUTPUT 参数返回多个值 | 必须有返回值(标量或表) |
| 使用场景 | 执行业务逻辑、数据处理 | 计算并返回一个值,或在查询中作为表使用 |
| 在 SELECT 中调用 | 不可以 | 可以 |
| DML 操作 | 可以对表进行所有 DML 操作 | 在函数内部不能执行 DML 操作(除了表变量) |
| 事务管理 | 可以在内部使用事务(BEGIN TRANSACTION) | 不能在函数内使用事务 |
| 执行方式 | EXEC/EXECUTE 过程名 | SELECT dbo.函数名() |
使用存储过程:
使用函数:
触发器:一种特殊的存储过程,在特定数据库事件(INSERT/UPDATE/DELETE)发生时自动执行。
AFTER 触发器(FOR 触发器):
inserted 和 deleted 魔术表INSTEAD OF 触发器:
这两个是触发器中的特殊内存表:
-- 在 UPDATE 触发器中
CREATE TRIGGER trg_AuditUpdate
ON Employees
AFTER UPDATE
AS
BEGIN
INSERT INTO AuditTable (EmployeeID, OldSalary, NewSalary)
SELECT d.EmployeeID, d.Salary, i.Salary
FROM deleted d
INNER JOIN inserted i ON d.EmployeeID = i.EmployeeID
WHERE d.Salary <> i.Salary;
END;
这三个都是窗口函数,用于为结果集的行分配排名:
SELECT
Name, Score,
ROW_NUMBER() OVER (ORDER BY Score DESC) as RowNum,
RANK() OVER (ORDER BY Score DESC) as Rank,
DENSE_RANK() OVER (ORDER BY Score DESC) as DenseRank
FROM Students;
递归 CTE 用于处理层次结构数据(如组织结构、菜单树等):
-- 查询某个部门及其所有子部门
WITH DepartmentCTE AS (
-- 锚定成员:根节点
SELECT DepartmentID, DepartmentName, ParentDepartmentID
FROM Departments
WHERE DepartmentID = @RootDepartmentID
UNION ALL
-- 递归成员:子节点
SELECT d.DepartmentID, d.DepartmentName, d.ParentDepartmentID
FROM Departments d
INNER JOIN DepartmentCTE cte ON d.ParentDepartmentID = cte.DepartmentID
)
SELECT * FROM DepartmentCTE;
参数嗅探:SQL Server 在编译存储过程时,使用第一次执行时的参数值来生成执行计划。如果后续执行的参数值数据分布差异很大,可能导致性能问题。
解决方案:
OPTION (RECOMPILE):每次执行都重新编译OPTION (OPTIMIZE FOR UNKNOWN):使用平均数据分布WITH RECOMPILE 选项创建存储过程查找慢查询:
-- 查找最耗时的查询
SELECT TOP 10
total_elapsed_time/execution_count AS avg_elapsed_time,
execution_count,
SUBSTRING(st.text, (qs.statement_start_offset/2)+1,
((CASE qs.statement_end_offset WHEN -1 THEN DATALENGTH(st.text)
ELSE qs.statement_end_offset END - qs.statement_start_offset)/2) + 1) AS statement_text
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
ORDER BY avg_elapsed_time DESC;
优化方法:
虽然范式化减少了数据冗余,但在以下情况可以考虑反范式化:
恢复场景示例:
完整备份 (周日) → 差异备份 (周一) → 日志备份 (周二 10:00) → 日志备份 (周二 11:00)
如果周二 11:30 发生故障,可以恢复到:周日完整备份 + 周一差异备份 + 周二 10:00 日志 + 周二 11:00 日志
简单恢复模式:
完整恢复模式:
-- 在表中添加删除标记字段
ALTER TABLE Products ADD IsDeleted BIT NOT NULL DEFAULT 0;
ALTER TABLE Products ADD DeletedDate DATETIME NULL;
-- 使用视图过滤已删除的记录
CREATE VIEW vw_ActiveProducts AS
SELECT * FROM Products WHERE IsDeleted = 0;
-- 使用 INSTEAD OF DELETE 触发器实现软删除
CREATE TRIGGER trg_SoftDeleteProduct
ON Products
INSTEAD OF DELETE
AS
BEGIN
UPDATE Products
SET IsDeleted = 1, DeletedDate = GETDATE()
WHERE ProductID IN (SELECT ProductID FROM deleted);
END;
方案1:使用延迟约束检查
ALTER TABLE TableA
ADD CONSTRAINT FK_TableA_TableB
FOREIGN KEY (BID) REFERENCES TableB(BID)
-- 在某些版本中可以使用 DEFERRABLE
方案2:允许 NULL 值,先插入部分数据再更新
方案3:使用触发器代替外键约束
方案4:重新设计表结构,消除循环引用
内存优化表将数据完全存储在内存中,提供极高的吞吐量:
适用场景:
创建示例:
CREATE TABLE dbo.SessionState
(
SessionID nvarchar(64) NOT NULL PRIMARY KEY NONCLUSTERED,
UserData varbinary(MAX) NOT NULL,
CreatedDate datetime2 NOT NULL
) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA);
变体示例:Color: Red,Green Size: S,M Style: A
变体组合结果:Red_S_A; Red_M_A; Green_S_A; Green_M_A
//测试用例
var list = new List<string[]>{
new string[]{"Red","Green"},
new string[]{"S","M"},
new string[]{"A"}
};
var result = Combine(list);
//期望result为:Red_S_A; Red_M_A; Green_S_A; Green_M_A
public List<string> Combine(List<string[]> list){ … }
public static List<string> Combine(List<string[]> list)
{
List<string> result = new List<string>();
int[] indices = new int[list.Count]; // 用于跟踪每个字符串数组中当前选取的元素的索引
while (true)
{
string combined = "";
for (int i = 0; i < list.Count; i++)
{
combined += "_" + list[i][indices[i]]; // 将当前索引对应的元素添加到组合中
}
result.Add(combined); // 将组合添加到结果列表中
// 更新索引
int j = list.Count - 1;
while (j >= 0 && indices[j] == list[j].Length - 1)
{
indices[j] = 0;
j--;
}
// 检查是否所有索引都已经达到最大值
if (j < 0)
{
break;
}
indices[j]++; // 增加索引
}
return result;
}
变体示例: Color: Red,Green Size: S,M Style: A,B
降维后:Color: Red,Green Size: S_A,S_B,M_A,M_B
var pair = new Dictionary<string, List<string>> {
{"Color",new List<string>{ "Red","Green" }},
{"Size",new List<string>{ "S","M" }},
{"Style",new List<string>{ "A","B" }},
};
var result = Reduce(pair);
public Dictionary<string, List<string>> Reduce(Dictionary<string, List<string>> pair){...}
class Program { static void Main() { // 定义变体维度 string[] colors = { "Red", "Green" }; string[] sizes = { "S", "M" }; string[] styles = { "A", "B" };
// 降维操作
Dictionary<string, string[]> reducedDimensions = ReduceDimensions(colors, sizes, styles);
// 打印降维后的变体
Console.WriteLine("Color: " + string.Join(",", reducedDimensions["Color"]));
Console.WriteLine("Size: " + string.Join(",", reducedDimensions["Size"]));
}
static Dictionary<string, string[]> ReduceDimensions(string[] colors, string[] sizes, string[] styles)
{
var reduced = new Dictionary<string, string[]>
{
{ "Color", colors },
{ "Size", sizes.SelectMany(size => styles.Select(style => size + "_" + style)).ToArray() }
};
return reduced;
}
}
S(sno, sname, sage, ssex):学号、姓名、年龄、性别SC(sno, cno, grade):学号、课程号、成绩C(cno, cname, teacher):课程号、课程名、教师名SELECT sname, sage FROM S AS X
WHERE x.ssex = '男' AND x.sage > ALL (
SELECT sage FROM S AS Y WHERE y.ssex = '女'
);
SELECT sname, sage FROM S
WHERE ssex = '男' AND sage > (
SELECT AVG(sage) FROM S WHERE ssex = '女'
);
SELECT sno, cno FROM SC WHERE grade IS NULL;
SELECT sname, sage FROM S WHERE sname LIKE 'WANG%';
SELECT sname FROM s
WHERE sno > (SELECT sno FROM s WHERE sname = 'WANG')
AND sage < (SELECT sage FROM s WHERE sname = 'WANG');
SELECT cno, COUNT(sno) AS 人数 FROM SC
GROUP BY cno HAVING COUNT(sno) > 2
ORDER BY 人数 DESC, cno ASC;
SELECT cname, AVG(grade) FROM SC, C
WHERE SC.cno = C.cno AND teacher = 'liu'
GROUP BY c.cno, cname;
SELECT AVG(sage) FROM S, SC
WHERE S.sno = SC.sno AND cno = '4';
SELECT COUNT(DISTINCT cno) FROM SC;
UPDATE SC SET grade = grade * 1.05 WHERE cno = '4' AND grade <= 75;
UPDATE SC SET grade = grade * 1.04 WHERE cno = '4' AND grade > 75;
UPDATE SC SET grade = grade * 1.05
WHERE grade < (SELECT AVG(grade) FROM SC)
AND sno IN (SELECT sno FROM S WHERE ssex = '女');
UPDATE SC SET grade = NULL
WHERE grade < 60 AND cno IN (
SELECT cno FROM C WHERE cname = '数据库原理'
);
DELETE FROM SC WHERE sno IN (
SELECT sno FROM S WHERE sname = 'WANG'
);
DELETE FROM SC WHERE grade IS NULL;
INSERT INTO S(sno, sname, sage) VALUES('S9', 'WU', 18);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。