基本 了解C#中的Task任务
C# 线程安全
业务场景:
当数据量达到一定量度,100w就会影响性能,如果达到500w-1kw (没有进行智能化分表储存)那查询一定是一个耗时耗力的慢查询
解决:
除了优化索引,优化表结构、优化查询语法
1、智能化分表储存 ,如表A 存 1-200w 条 ;表B存 201w-400w 条;表C 存 401W-600w 条 (需要一些逻辑算法,其次取中间 数据比较麻烦)
2、线程 + 分页查询
CREATE TABLE TEX
(
[Id] [INT] NOT NULL IDENTITY(1, 1),
[UserName1] [VARCHAR](255) NOT NULL,
[UserName2] [VARCHAR](255) NOT NULL,
[UserName3] [VARCHAR](255) NOT NULL,
[UserName4] [VARCHAR](255) NOT NULL,
[UserName5] [VARCHAR](255) NOT NULL,
[UserName6] [VARCHAR](255) NOT NULL,
[UserName7] [VARCHAR](255) NOT NULL,
[UserName8] [VARCHAR](255) NOT NULL,
[UserName9] [VARCHAR](255) NOT NULL,
[UserName10] [VARCHAR](255) NOT NULL,
[UserName11] [VARCHAR](255) NOT NULL,
[UserName12] [VARCHAR](255) NOT NULL,
[UserName13] [VARCHAR](255) NOT NULL,
[UserName14] [VARCHAR](255) NOT NULL,
[UserName15] [VARCHAR](255) NOT NULL
);
ALTER TABLE dbo.TEX ADD CONSTRAINT PK_TEX_ID PRIMARY KEY(Id)
DECLARE @Count INT =0;
DECLARE @UserName VARCHAR(255)=CONVERT(VARCHAR(255),NEWID());
WHILE @Count < 6000000
BEGIN
INSERT INTO dbo.TEX
(
UserName1,UserName2,UserName3,UserName4,UserName5,UserName6,UserName7,UserName8,
UserName9,UserName10,UserName11,UserName12,UserName13,UserName14,UserName15
)
VALUES
(@UserName,@UserName,@UserName,@UserName,@UserName,@UserName,@UserName,@UserName,
@UserName,@UserName,@UserName,@UserName,@UserName,@UserName,@UserName);
SET @Count = @Count + 1;
END;
PRINT @Count;
为了方便测试使用dbhelper链接数据库类 项目里最好可以换成ef core 或者 sqlsugar 会更好
static void Main(string[] args)
{
//程序启动时间
Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
Taskt2(); //执行的线程
Console.ReadKey();
}
///执行的线程
public static void Taskt2()
{
//为了方便dbhelper链接数据库类 项目里最好可以换成ef core 或者 sqlsugar 会更好
SQLServerDataBase dataBase = new SQLServerDataBase();
DataSet dataSet = new DataSet();
var stus = dataBase.ExecuteNonDataSet("SELECT MAX(id) AS ID FROM dbo.TEX", out dataSet); //获取总页数
long suncount = Convert.ToInt64(dataSet.Tables[0].Rows[0]["ID"]); //600w条数据
int pagesize = 500000; //设置每页多少条
double pagecount = Math.Ceiling(Convert.ToDouble(suncount / pagesize)); //总页数 有余数向上取整
var blockingCollection = new BlockingCollection<string>(); // BlockingCollection 线程安全集合
Task Taskproducer = Task.Factory.StartNew(() =>
{
for (int count = 1; count <= pagecount; count++)
{
blockingCollection.Add(count.ToString()); //添加分页页码
Thread.Sleep(3500);
}
blockingCollection.CompleteAdding(); //添加完成
});
//多线程 执行 查询
Task[] taskArray = new Task[6]; //6个task任务
for (int i = 0; i < taskArray.Length; i++)
{
taskArray[i] = Task.Factory.StartNew(() =>
{
foreach (string value in blockingCollection.GetConsumingEnumerable())
{
string iResult = PageData(pagesize, Convert.ToInt32(value));
Console.WriteLine($@"Worker {Thread.CurrentThread.ManagedThreadId}:
第{value}页 {iResult} {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");
}
});
}
Task.WaitAll(taskArray); //设置等待
}
///分页sql
///如果是 ef core 或者 sqlsugar 这里最好用 linq 查询 返回list
public static string PageData(int PageSize,int CurrentPage)
{
SQLServerDataBase dataBase = new SQLServerDataBase();
DataSet dataSet = new DataSet();
string sql = $@"
SELECT *
FROM TEX
ORDER BY Id
OFFSET ({PageSize} * ({CurrentPage} - 1)) ROW FETCH NEXT {PageSize} ROWS ONLY;";
dataBase.ExecuteNonDataSet(sql, out dataSet);
//获取每一页的第一个行和最后一行的id
int min= Convert.ToInt32(dataSet.Tables[0].Rows[0]["Id"]);
int max = Convert.ToInt32(dataSet.Tables[0].Rows[PageSize-1]["Id"]);
return $@"查询: {min} 到 {max} 行";
}
Worker 4、7、5、9、10、11 对应的 Task[] taskArray = new Task[6]; //6个task任务