但最近改版時產生異常,變成一部機器有多筆資料,導致執行計畫沒有從該 Table 起跑,兩個重點 Table 資料量大約是 150 萬筆和 50 萬筆,通通都被拉出來篩選,CPU Time 超過 1 秒
整理 Table 內資料,執行計畫就恢復正常啦
改善前後比較
改善前 | 改善後 | |
---|---|---|
CPU Time | 1,282 | 16 |
50 萬 Table Logical Read | 14,857 | 284 |
150 萬 Table Logical Read | 16,484 | 294 |
Any comparison operator other than "=" expresses inequality.
WHERE ColumnId5 IN ('資料1', '資料2', '資料3', '資料4')
SELECT
M.ColumnId5
,M.ColumnId11
,M.ColumnId12
,M.ColumnId27
FROM TableName AS M
JOIN
(
SELECT
ColumnId5 ,
MAX(ColumnId29) AS ColumnId29
FROM TableName
WHERE ColumnId5 IN ('資料1', '資料2', '資料3', '資料4')
AND ColumnId23 > 0
GROUP BY ColumnId5
) AS T ON M.ColumnId5 = T.ColumnId5
AND M.ColumnId29 = T.ColumnId29
WHERE M.ColumnId23 > 0
WHERE ColumnId5 IN ('資料1', '資料2', '資料3', '資料4')
AND ColumnId23 > 0
- List the equality columns first (leftmost in the column list).
- List the inequality columns after the equality columns (to the right of equality columns listed).
- List the include columns in the INCLUDE clause of the CREATE INDEX statement.
- To determine an effective order for the equality columns, order them based on their selectivity; that is, list the most selective columns first.
Review the missing index recommendations for a table as a group, along with the definitions of existing indexes on the table. Remember that when defining indexes, generally equality columns should be put before the inequality columns, and together they should form the key of the index. To determine an effective order for the equality columns, order them based on their selectivity: list the most selective columns first (leftmost in the column list). Unique columns are most selective, while columns with many repeating values are less selective.Included columns should be added to the CREATE INDEX statement using the INCLUDE clause. The order of included columns doesn't affect query performance. Therefore, when combining indexes, included columns may be combined without worrying about order
CREATE INDEX IX_TableName ON TableName( ColumnId5 )
改善前 | 改善後 | |
---|---|---|
Logical Read | 11,766 | 2,098 |
USE tempdb
GO
DROP TABLE IF EXISTS tblMaster
DROP TABLE IF EXISTS tblDetail
CREATE TABLE tblMaster (ColPK CHAR(11))
CREATE TABLE tblDetail (ID INT IDENTITY(1,1) , ColPK char(11))
SELECT
CASE
WHEN D.ColPK IS NOT NULL THEN 1 -- 字串欄位轉為整數
ELSE D.ColPK
END AS Test1 ,
IIF(D.ColPK IS NOT NULL , 1 , D.ColPK) AS Test2
FROM tblMaster AS M
LEFT JOIN tblDetail AS D ON M.ColPK = D.ColPK
using System;
namespace ConsoleApp2
{
internal class Program
{
static void Main(string[] args)
{
string data = "AB-20231013";
bool isValid = false;
if (data.Length == 11)
{
if (data.Substring(0, 2) == "AB")
{
if (data.Substring(2, 1) == "-") ;
{
string date = data.Substring(3, 8);
isValid = DateTime.TryParseExact(
date,
"yyyyMMdd",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None,
out DateTime result);
}
}
}
Console.WriteLine($"驗證結果為 {isValid}");
}
}
}
Designe Pattern:責任鍊來消除 IfElse
using System;
namespace ConsoleApp2
{
internal class Program
{
static void Main(string[] args)
{
string data = "AB-20231013";
AbstractHandler chain = new 總長度Handler(
new 前兩碼Hanlde(
new 符號Handler(
new 日期Handle(null))));
bool isValid = chain.HandleRequest(data);
Console.WriteLine($"驗證結果為 {isValid}");
}
}
public class 日期Handle : AbstractHandler
{
public 日期Handle(AbstractHandler successor) : base(successor)
{
}
protected override bool Handle(string request)
{
string date = request.Substring(3, 8);
return DateTime.TryParseExact(
date,
"yyyyMMdd",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None,
out DateTime result);
}
}
public class 符號Handler : AbstractHandler
{
public 符號Handler(AbstractHandler successor) : base(successor)
{
}
protected override bool Handle(string request)
{
return (request.Substring(2, 1) == "-");
}
}
public class 前兩碼Hanlde : AbstractHandler
{
public 前兩碼Hanlde(AbstractHandler successor) : base(successor)
{
}
protected override bool Handle(string request)
{
return (request.Substring(0, 2) == "AB");
}
}
public class 總長度Handler : AbstractHandler
{
public 總長度Handler(AbstractHandler successor) : base(successor)
{
}
protected override bool Handle(string request)
{
return (request.Trim().Length == 11);
}
}
public abstract class AbstractHandler
{
private AbstractHandler _successor;
public AbstractHandler(AbstractHandler successor)
{
_successor = successor;
}
protected abstract bool Handle(string request);
public bool HandleRequest(string request)
{
if (Handle(request) == false)
return false;
if (_successor == null)
return true;
return _successor.HandleRequest(request);
}
}
}
USE [AdventureWorks2022]
GO
/****** Object: Table [Person].[Person] Script Date: 2023/10/10 下午 10:32:11 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [Person].[Person](
[BusinessEntityID] [int] NOT NULL,
[PersonType] [nchar](2) NOT NULL,
[NameStyle] [dbo].[NameStyle] NOT NULL,
[Title] [nvarchar](8) NULL,
[FirstName] [dbo].[Name] NOT NULL,
[MiddleName] [dbo].[Name] NULL,
[LastName] [dbo].[Name] NOT NULL,
[Suffix] [nvarchar](10) NULL,
[EmailPromotion] [int] NOT NULL,
[AdditionalContactInfo] [xml](CONTENT [Person].[AdditionalContactInfoSchemaCollection]) NULL,
[Demographics] [xml](CONTENT [Person].[IndividualSurveySchemaCollection]) NULL,
[rowguid] [uniqueidentifier] ROWGUIDCOL NOT NULL,
[ModifiedDate] [datetime] NOT NULL,
CONSTRAINT [PK_Person_BusinessEntityID] PRIMARY KEY CLUSTERED
(
[BusinessEntityID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
INSERT [Person].[Person] ([BusinessEntityID], [PersonType], [NameStyle], [Title], [FirstName], [MiddleName], [LastName], [Suffix], [EmailPromotion], [AdditionalContactInfo], [Demographics], [rowguid], [ModifiedDate]) VALUES (1, N'EM', 0, NULL, N'Ken', N'J', N'Sánchez', NULL, 0, NULL, N'<IndividualSurvey xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/IndividualSurvey"><TotalPurchaseYTD>0</TotalPurchaseYTD></IndividualSurvey>', N'92c4279f-1207-48a3-8448-4636514eb7e2', CAST(N'2009-01-07T00:00:00.000' AS DateTime))
INSERT [Person].[Person] ([BusinessEntityID], [PersonType], [NameStyle], [Title], [FirstName], [MiddleName], [LastName], [Suffix], [EmailPromotion], [AdditionalContactInfo], [Demographics], [rowguid], [ModifiedDate]) VALUES (2, N'EM', 0, NULL, N'Terri', N'Lee', N'Duffy', NULL, 1, NULL, N'<IndividualSurvey xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/IndividualSurvey"><TotalPurchaseYTD>0</TotalPurchaseYTD></IndividualSurvey>', N'd8763459-8aa8-47cc-aff7-c9079af79033', CAST(N'2008-01-24T00:00:00.000' AS DateTime))
INSERT [Person].[Person] ([BusinessEntityID], [PersonType], [NameStyle], [Title], [FirstName], [MiddleName], [LastName], [Suffix], [EmailPromotion], [AdditionalContactInfo], [Demographics], [rowguid], [ModifiedDate]) VALUES (3, N'EM', 0, NULL, N'Roberto', NULL, N'Tamburello', NULL, 0, NULL, N'<IndividualSurvey xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/IndividualSurvey"><TotalPurchaseYTD>0</TotalPurchaseYTD></IndividualSurvey>', N'e1a2555e-0828-434b-a33b-6f38136a37de', CAST(N'2007-11-04T00:00:00.000' AS DateTime))
INSERT [Person].[Person] ([BusinessEntityID], [PersonType], [NameStyle], [Title], [FirstName], [MiddleName], [LastName], [Suffix], [EmailPromotion], [AdditionalContactInfo], [Demographics], [rowguid], [ModifiedDate]) VALUES (4, N'EM', 0, NULL, N'Rob', NULL, N'Walters', NULL, 0, NULL, N'<IndividualSurvey xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/IndividualSurvey"><TotalPurchaseYTD>0</TotalPurchaseYTD></IndividualSurvey>', N'f2d7ce06-38b3-4357-805b-f4b6b71c01ff', CAST(N'2007-11-28T00:00:00.000' AS DateTime))
INSERT [Person].[Person] ([BusinessEntityID], [PersonType], [NameStyle], [Title], [FirstName], [MiddleName], [LastName], [Suffix], [EmailPromotion], [AdditionalContactInfo], [Demographics], [rowguid], [ModifiedDate]) VALUES (5, N'EM', 0, N'Ms.', N'Gail', N'A', N'Erickson', NULL, 0, NULL, N'<IndividualSurvey xmlns="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/IndividualSurvey"><TotalPurchaseYTD>0</TotalPurchaseYTD></IndividualSurvey>', N'f3a3f6b4-ae3b-430c-a754-9f2231ba6fef', CAST(N'2007-12-30T00:00:00.000' AS DateTime))
指令碼精雖然方便把資料轉出成 Script 來使用,但不建議使用就是,之前有過一萬筆左右 Table,在 Local 端透過指令碼精靈轉出,在離峰時間拿到 Product 環境上去進行 insert,花了快 10 分鐘才完成,有點出乎意外之外的慢,之後就乖乖的使用 bcp out 把資料倒出,bcp in 或 bulk insert 匯入資料比較快速