SELECT
在 ISO/IEC 标准中,SQL 为子条款规定了以下语法顺序:
SELECT
projection-expressions
FROM
sources
WHERE
predicate-expression
GROUP BY
key-expression
HAVING
predicate-expression
ORDER BY
ordering-expressions
Run Code Online (Sandbox Code Playgroud)
虽然逻辑执行顺序是这样的:
FROM
sources
WHERE
predicate-expression
GROUP BY
value-expression
HAVING
value-expression
SELECT
projection-expressions
ORDER BY
ordering-expressions
Run Code Online (Sandbox Code Playgroud)
对于 SQL 的新手用户来说,即使它是首先声明的,在SELECT
子句中定义的投影在WHERE
or子句中不可用,这变得令人惊讶GROUP BY
- 考虑到计算机程序通常遵循自上而下的执行顺序。
同样令人惊讶的是,SQL 作者需要在、 和子句中重复他们的表达式SELECT
,或者使用不适合简洁查询的子查询。至少当用户熟悉实际的子句执行顺序时,他们知道为什么需要重复自己,但这并不能阻止它令人沮丧。WHERE
GROUP BY
这个问题和其他相关问题记录在我发现的这篇文章中:https : //blog.jooq.org/a-beginners-guide-to-the-true-order-of-sql-operations/,这并不奇怪StackOverflow 上的 QA 有近 30,000 次查看:https : //stackoverflow.com/questions/3241352/using-an-alias-column-in-the-where-clause-in-postgresql
这让我想知道是否有任何 SQL 实现允许这种更“合乎逻辑”的子句排序。我注意到 .NET 中的 Linq 实际上确实遵循这个顺序,虽然我不会将它描述为真正的 SQL 实现,但实际上,在 Linq …
(我不认为这个问题是8 年前这个问题的重复,因为我不是问超大列的优点,我问的是下面链接文章中展示的行为。)
从SQLPerformance.com这最近(2017年)的文章演示了如何改变最大长度n
为一varchar(n)
列影响查询计划行大小估计和排序缓冲区的大小估计会导致欠佳的性能和内存分配警告。
在其中,作者声称(强调我的):
从这里我们看到,列定义越大,估计的行和数据大小就越大。在这个简单的查询中,无论定义如何,所有查询的 I/O 成本 (0.0512731) 都是相同的,因为聚集索引扫描无论如何都必须读取所有数据。
但在其他情况下,此估计行和总数据大小会产生影响:需要额外资源的操作,例如排序。
当我读到那个声明(以粗体显示)时,我感到很惊讶,因为我认为 SQL Server 会从STATISTICS
在这些相同表上维护的采样对象中获得相当准确的行大小估计。特别是考虑到SELECT AVG(LEN(email))
文章中的查询显示没有列的值超过 77 个字符。
这篇文章还明确地执行了一个ALTER INDEX ALL ON dbo.Table REBUILD
-这个 DB.SE 帖子说它也将自动更新STATISTICS
。
(虽然我很惊讶 SQLPerformance 文章中根本没有出现“统计”这个词——所以也许在作者的情况下,由于某些机器配置,统计数据根本没有更新,他们没有注意到?)
SQL Server 是否仅对varchar
行大小估计使用列长度限制?如果不是,那么为什么 SQLPerformance 文章描述相同?
SQL Server 允许在约束中使用用户定义函数 (UDF) CHECK
- 它有许多用例 - 我不会深入讨论 - 但我最近面临着实现一个经过验证的重要业务/域约束一个表中的数据基于另一表中的非唯一、非关键数据 - 这意味着该约束不能使用任何内置约束(FOREIGN KEY
、UNIQUE
或基于普通行值的CHECK
约束)来实现。
我立即选择的是TRIGGER
,因为微软自己的文档指出TRIGGER
对象是实现非平凡约束的预期方式:
当约束支持的功能无法满足应用程序的功能需求时,DML 触发器最有用。[...] 与
CHECK
约束不同,DML 触发器可以引用其他表中的列。例如,触发器可以使用SELECT
另一个表中的数据来与插入或更新的数据进行比较,并执行其他操作,例如修改数据或显示用户定义的错误消息。
稍等一下:Microsoft 写道“与CHECK
约束不同,DML 触发器可以引用其他表中的列” - 但这是误导性的!CHECK
约束可以通过 UDF 间接引用其他表中的列。
...所以我认为那里有一些模糊和过时的信息 - 所以让我们做更多的研究来看看CHECK
UDF 的约束是否是正确的方法...
...好吧,CHECK
约束中的 UDF 似乎名声不好:有关于性能不佳和缺乏形式正确性的批评评论(一个获胜的组合......),但我注意到我读过的文章和帖子,包括实际上,所有有关 UDF 和CHECK
约束的 Google 搜索结果都是旧的......
Google 搜索结果中排名第一的“sql server check constraint udf”是一篇可以追溯到2001 年 …
Supposing I have this table (in a multi-tenant SaaS database:
CREATE TABLE dbo.Messages (
TenantId int NOT NULL,
RecipientId int NOT NULL,
MessageId int NOT NULL IDENTITY,
SentUtc datetime2(7) NOT NULL,
IsDeleted bit NOT NULL, /* Less than 5% of rows have IsDeleted = 1 */
-- Body, Subject, etc
CONSTRAINT PK_Messages PRIMARY KEY ( MessageId, TenantId ),
CONSTRAINT UK_Messages UNIQUE ( MessageId ),
CONSTRAINT FK_Messages_Tenants FOREIGN KEY ( TenantId ) REFERENCES dbo.Tenants ( TenantId ),
CONSTRAINT FK_Messages_Recipients FOREIGN KEY …
Run Code Online (Sandbox Code Playgroud) 我有一个包含大约 200 万行的 SQL Server 表,该表存储简短的文本文档。这是我的架构:
CREATE TABLE Documents (
documentId bigint IDENTITY NOT NULL,
content nvarchar(MAX) NOT NULL,
isIndexed bit NOT NULL
)
Run Code Online (Sandbox Code Playgroud)
我有一个单独的基于 Lucene 的索引器进程来执行此操作:
SELECT TOP 1 documentId, content FROM Documents WHERE isIndexed = 0
Run Code Online (Sandbox Code Playgroud)
然后在执行此操作之前执行索引操作:
UPDATE Documents SET isIndexed = 1 WHERE documentId = @documentId
Run Code Online (Sandbox Code Playgroud)
最初这工作正常。当表中的每个文档都没有被索引时(即所有isIndexed
值都是 0),那么每次检索大约需要 5 毫秒。
然而,随着越来越多的文档被索引,检索时间慢慢增加。目前大约是 150 毫秒 - 速度降低了 30 倍。我注意到 UPDATE 语句似乎总是在 2 毫秒内运行,所以我知道这不是问题。
从一开始,表在 isIndexed 列上一直有一个非聚集索引,但实际执行计划显示 SQL Server 使用索引扫描(而不是搜索)。
我可以做些什么来加速系统?
我知道现有的“isIndexed”列本身很糟糕,但由于索引器的工作方式,它无法直接通过 documentId 请求文档。由于这个原因和其他原因,我不能接受任何不能解决手头直接问题的答案。
我有一张表存储客户信息(您的沼泽标准 CRM 资料):
CREATE TABLE dbo.Customers (
TenantId int NOT NULL,
CustomerId int NOT NULL,
FirstName nvarchar(50) NOT NULL DEFAULT '',
LastName nvarchar(50) NOT NULL DEFAULT '',
CompanyName nvarchar(50) NOT NULL DEFAULT '',
Notes nvarchar(4000) NOT NULL DEFAULT ''
)
Run Code Online (Sandbox Code Playgroud)
此表最近已转换为 SQL Server 时态表:
ALTER TABLE dbo.Customers
ADD COLUMN
SysStart datetime2(7) GENERATED ALWAYS AS ROW START NOT NULL,
SysEnd datetime2(7) GENERATED ALWAYS AS ROW END NOT NULL;
GO
ALTER TABLE dbo.Customers WITH (
PERIOD FOR SYSTEM_TIME ( SysStart, SysEnd ), …
Run Code Online (Sandbox Code Playgroud)