小编Joh*_*ohn的帖子

Sql Server 无法在简单双射上使用索引

这是另一个查询优化器难题。

也许我只是高估了查询优化器,或者我遗漏了一些东西 - 所以我把它放在那里。

我有一张简单的桌子

CREATE TABLE [dbo].[MyEntities](
  [Id] [uniqueidentifier] NOT NULL,
  [Number] [int] NOT NULL,
  CONSTRAINT [PK_dbo.MyEntities] PRIMARY KEY CLUSTERED ([Id])
)

CREATE NONCLUSTERED INDEX [IX_Number] ON [dbo].[MyEntities] ([Number])
Run Code Online (Sandbox Code Playgroud)

有一个索引和几千行,Number均匀分布在值 0、1 和 2 中。

现在这个查询:

SELECT * FROM
    (SELECT
        [Extent1].[Number] AS [Number],
        CASE
        WHEN (0 = [Extent1].[Number]) THEN 'one'
        WHEN (1 = [Extent1].[Number]) THEN 'two'
        WHEN (2 = [Extent1].[Number]) THEN 'three'
        ELSE '?'
        END AS [Name]
        FROM [dbo].[MyEntities] AS [Extent1]
        ) P
WHERE P.Number = 0;
Run Code Online (Sandbox Code Playgroud)

是否 …

sql-server execution-plan sql-server-2016

11
推荐指数
3
解决办法
776
查看次数

为什么SQL Server不做复合列统计直方图?

SQL Server 有一种叫做“多列统计”的东西,但这并不是人们认为的意思。

我们来看看下面的示例表:

CREATE TABLE BadStatistics 
(
    IsArchived BIT NOT NULL,
    Id INT NOT NULL IDENTITY PRIMARY KEY,
    Mystery VARCHAR(200) NOT NULL
);

CREATE NONCLUSTERED INDEX BadIndex 
    ON BadStatistics (IsArchived, Mystery);
Run Code Online (Sandbox Code Playgroud)

这样,我们就在我们拥有的两个索引上创建了两个统计信息:

BadIndex 的统计数据:

+--------------+----------------+-------------------------+
| All density  | Average Length | Columns                 |
+--------------+----------------+-------------------------+
| 0.5          | 1              | IsArchived              |
+--------------+----------------+-------------------------+
| 4.149378E-06 | 37             | IsArchived, Mystery     |
+--------------+----------------+-------------------------+
| 4.149378E-06 | 41             | IsArchived, Mystery, Id |
+--------------+----------------+-------------------------+

+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS …
Run Code Online (Sandbox Code Playgroud)

sql-server statistics

10
推荐指数
1
解决办法
1333
查看次数

索引查找特定的多列键,然后按字典顺序获取一些行

考虑以下具有多列索引的示例表:

create table BigNumbers (
    col1 tinyint not null,
    col2 tinyint not null,
    col3 tinyint not null,

    index IX_BigNumbers clustered (col1, col2, col3)
)

DECLARE @n INT = 100;

DECLARE @x1 INT = 0;
DECLARE @x2 INT = 0;
DECLARE @x3 INT = 0;

SET NOCOUNT ON;

WHILE @x3 <= @n BEGIN
    SET @x2 = 0;
    WHILE @x2 <= @n BEGIN
        SET @x1 = 0;
        WHILE @x1 <= @n BEGIN
            insert into BigNumbers values (@x1, @x2, @x3);
            SET @x1 = …
Run Code Online (Sandbox Code Playgroud)

index sql-server btree

8
推荐指数
2
解决办法
951
查看次数

相似匹配与比较之间的关系

like \'foo%\'我天真地认为 a和 a之间的关系>= \'foo\'是后者与前者以及索引顺序中后面的一些附加行相匹配。更一般地说,我认为对于给定的文本,t字符列上的索引分为四个区域,分别是

\n
    \n
  1. <( )之前的条目t
  2. \n
  3. 条目等于 ( =) t
  4. \n
  5. >大于 ( )t且仍以t( ) 作为前缀的条目like concat(t, \'%\')以及
  6. \n
  7. 其余的部分,
  8. \n
\n

并且这些区域是连续的并且按顺序排列。

\n

此外,具有t前缀 ( like concat(t, \'%\')) 的所有行也在索引中形成一个连续区域,并且该区域在其开头包含区域 2(这意味着它恰好是区域 2 和 3 在一起)。

\n

但事情可能没那么简单。例如,在 SQL Server 中,单词在排序规则中H\xc3\xa4user比较等于,并且两者都是。HaeuserGerman_PhoneBook_CI_AI>= \'Ha\'

\n

但是,仅Haeuser匹配like \'Ha%\',因此有关前缀的附加假设并不完全成立。

\n

你可以在这个小提琴中看到这一点。 …

sql-server collation order-by

7
推荐指数
1
解决办法
427
查看次数

在查找子串时,也要查找结束位置

子句LIKE可以测试某个字符串是否出现在另一个字符串中,并且该CHARINDEX函数可以给出第一个匹配的开始位置。

\n

就我而言,我对结束位置感兴趣,由于排序规则的复杂性,它无法从开始位置推导出来。例如,在德语排序规则 ( German_PhoneBook_100_CI_AS_SC_UTF8) 中,

\n
    \n
  • h\xc3\xa4出现在 'H\xc3\xa4ger' 的位置 1 处,结束于位置 2 处
  • \n
  • h\xc3\xa4出现在“Haeger”中的位置 1 并结束于位置 3。
  • \n
\n

这样做的问题是为了用户的利益标记搜索结果文本的匹配部分。

\n

我一直在考虑反转字符串,但我仍然只能得到第一个匹配项CHARINDEX,在反转的情况下我需要最后一个匹配项。

\n

有人有什么想法吗?

\n

sql-server collation substring

5
推荐指数
1
解决办法
830
查看次数

为什么我的执行计划(有时)包括左连接?

我发现了一个类似的问题,我知道为了查询表格

SELECT COUNT(1)
FROM foo f
LEFT OUTER JOIN bar b ON f.Value = b.Value AND f.Value = b.Value2
Run Code Online (Sandbox Code Playgroud)

要在不接触的情况下执行bar,需要在有问题的两列上有一个唯一索引。

事实上,到目前为止,这有效,表被定义为:

CREATE TABLE [dbo].[Foo](
    [Value] [varchar](255) NOT NULL
) ON [PRIMARY]

CREATE TABLE [dbo].[Bar](
    [Value] [varchar](1024) NULL,
    [Value2] [varchar](1024) NULL
)

CREATE UNIQUE CLUSTERED INDEX [IX] ON [dbo].[Bar]
(
    [Value] ASC,
    [Value2] ASC
)
Run Code Online (Sandbox Code Playgroud)

查询计划没有触及bar,太好了。

在我探索为什么这在我编写的某些应用程序的实际查询中不起作用时,我将那里的查询简化为以下简单的测试,并且查询计划器无法将其从桌子上移开bar

WITH numbers AS (
    SELECT 1 AS i
    UNION ALL SELECT i + 1
    FROM numbers …
Run Code Online (Sandbox Code Playgroud)

join sql-server execution-plan sql-server-2014

4
推荐指数
1
解决办法
576
查看次数

快照隔离级别下编写者相互锁定的要点

SQL Server 中的读已提交快照和快照隔离级别消除了大多数锁定,除了以下一种情况:一个写入者仍会锁定其他写入者

该文档小心翼翼地说了这么多,随后没有记录任何其他值得了解的内容:

它真的只是被独占锁定的修改行吗?或者它也可以是不相关的行(例如索引中相邻的行)或页面?

我确实查看了其中的锁sys.dm_tran_locks,并且在未提交的事务期间只看到了修改行上的独占锁 - 页面仅被锁定为IX.

我还测试了两个事务是否可以在一个非常小的表(可能适合一页)中的两个未提交事务期间同时修改两个不同的行,并且效果也很好。

如果确实只有修改的行被独占锁定,那么如果确保没有两个连接同时写入同一行,那么这将为具有数据库独占访问权限的应用程序提供无锁写入的保证。

在我想到的场景中这是可能的 - 但如果页面锁发挥作用,几乎没有办法做类似的事情,因为无法预测哪些行到底会受到影响。

sql-server transaction locking snapshot-isolation

3
推荐指数
1
解决办法
406
查看次数

物化视图和查询计划中的分组依据

部分出于好奇,我想知道是否可以使用索引(物化)视图来加速对某个基表的计数查询。

查询类似于

SELECT COUNT(*)
FROM BaseTable
WHERE Slot = ?;
Run Code Online (Sandbox Code Playgroud)

所以我创建了一个视图

CREATE VIEW IndexedView
WITH SCHEMABINDING AS
SELECT bt.Slot, COUNT_BIG(*) AS COUNT
FROM dbo.BaseTable bt
GROUP BY bt.Slot;
Run Code Online (Sandbox Code Playgroud)

有聚集索引

CREATE UNIQUE CLUSTERED INDEX IX_Main
ON IndexedView (Slot);
Run Code Online (Sandbox Code Playgroud)

这有效,我现在可以将原始查询编写为

SELECT COUNT
FROM IndexedView
WHERE Slot = ?
Run Code Online (Sandbox Code Playgroud)

并更快地获得所需的结果。

唉,这对我来说没什么用,因为我的查询通常不是手工制作的。我真的需要通过使用索引视图作为某种索引来使原始查询变得更快BaseTable- 我想我在某处读到这可能在某些情况下发生,但根据我的测试,而不是在这个测试中。

所以我的问题是:

  • 在这种情况下,索引视图还能以某种方式帮助我吗?
  • 任何人都可以推荐来源/文献而不是解释在哪些情况下索引视图确实用于优化它们所基于的表的查询?

编辑:关于重复的问题 - 我对 GROUP BY 和索引视图的聚合方面更感兴趣。答案帮助我找到了我犯的一个愚蠢的错误,现在它也对我有用。

JOYOUS ADDENDUM:现在我让它工作了,我成功地测试了它甚至可以在查询包含左联接的情况下工作,而在这些情况下,左联接实际上可以被优化掉(即 on-clause 涵盖了一个唯一索引在连接表中)。

这真的很棒,因为这意味着即使在带有左连接的查询的情况下,也可以以这样一种方式设计模式,即快速获取所有内容或特定分组的总行数。

sql-server materialized-view

1
推荐指数
1
解决办法
493
查看次数