我想根据日期检索所有登录日志。另外我需要JQuery-datatable排序和搜索的所有功能!我曾经研究过许多查询和数据表,但这个问题比我想象的要困难。
CREATE PROCEDURE [dbo].[sp_login_logs]
(
@sp_start_date DATETIME,
@sp_end_date DATETIME,
@sp_offset INT,
@sp_count INT,
@sp_search VARCHAR(MAX),
@sp_sort INT
)
AS
BEGIN
SELECT table1.email,table1.city,table1.latitude,table1.longitude,table1.first_log,
table1.last_log,table1.platform,table1.app
FROM (SELECT ll.email,
ISNULL(ll.city,'') city,
ll.latitude,
ll.longitude,
(SELECT min(insertdate)
FROM [LoginLog]
WHERE email=ll.email) AS first_log,
ll.insertdate AS last_log,
CASE
WHEN platform LIKE '%iPhone%'
OR platform LIKE '%Darwin%'
OR platform LIKE '%iPad%'
OR platform LIKE '%iOS%' THEN 'iPhone'
ELSE CASE
WHEN platform LIKE '%Android%'
OR platform LIKE '%Apache%' THEN 'Android'
ELSE 'iPhone'
END
END AS platform,
CASE
WHEN app IS NULL THEN 'Consumer'
ELSE App
END AS app
FROM [LoginLog] ll
WHERE id =
(SELECT max(id)
FROM [LoginLog] ll2
WHERE ll2.email =ll.email
AND
(ll2.email like '%'+@sp_search+'%'OR
ll2.city like '%'+@sp_search+'%'OR
ll2.latitude like '%'+@sp_search+'%'OR
ll2.longitude like '%'+@sp_search+'%'
)
)
AND ll.email<>'' AND ll.email<>'(null)'
AND ll.insertdate>@sp_start_date AND ll.insertdate<@sp_end_date
AND loginsucess=1 and isnull(Country, 'United States')='United States'
) AS table1
WHERE(
table1.first_log like '%'+@sp_search+'%'OR
table1.last_log like '%'+@sp_search+'%'OR
table1.platform like '%'+@sp_search+'%'OR
table1.app like '%'+@sp_search+'%'
)
ORDER BY
CASE WHEN (@sp_sort%100 = 01 and ((@sp_sort%1000)/100) = 1) THEN table1.email END ASC,
CASE WHEN (@sp_sort%100 = 01 and ((@sp_sort%1000)/100) = 0) THEN table1.email END DESC,
CASE WHEN (@sp_sort%100 = 02 and ((@sp_sort%1000)/100) = 1) THEN table1.city END ASC,
CASE WHEN (@sp_sort%100 = 02 and ((@sp_sort%1000)/100) = 0) THEN table1.city END DESC,
CASE WHEN (@sp_sort%100 = 03 and ((@sp_sort%1000)/100) = 1) THEN table1.latitude END ASC,
CASE WHEN (@sp_sort%100 = 03 and ((@sp_sort%1000)/100) = 0) THEN table1.latitude END DESC,
CASE WHEN (@sp_sort%100 = 04 and ((@sp_sort%1000)/100) = 1) THEN table1.longitude END ASC,
CASE WHEN (@sp_sort%100 = 04 and ((@sp_sort%1000)/100) = 0) THEN table1.longitude END DESC,
CASE WHEN (@sp_sort%100 = 05 and ((@sp_sort%1000)/100) = 1) THEN table1.first_log END ASC,
CASE WHEN (@sp_sort%100 = 05 and ((@sp_sort%1000)/100) = 0) THEN table1.first_log END DESC,
CASE WHEN (@sp_sort%100 = 06 and ((@sp_sort%1000)/100) = 1) THEN table1.last_log END ASC,
CASE WHEN (@sp_sort%100 = 06 and ((@sp_sort%1000)/100) = 0) THEN table1.last_log END DESC,
CASE WHEN (@sp_sort%100 = 07 and ((@sp_sort%1000)/100) = 1) THEN table1.platform END ASC,
CASE WHEN (@sp_sort%100 = 07 and ((@sp_sort%1000)/100) = 0) THEN table1.platform END DESC,
CASE WHEN (@sp_sort%100 = 08 and ((@sp_sort%1000)/100) = 1) THEN table1.app END ASC,
CASE WHEN (@sp_sort%100 = 08 and ((@sp_sort%1000)/100) = 0) THEN table1.app END DESC
OFFSET @sp_offset ROWS
FETCH NEXT @sp_count ROWS Only
END
这样可以正常运行但耗费大量内存和时间......不能等待5分钟,其中有超过数百万条记录。
如果有人需要,这是我的表格:
CREATE TABLE [dbo].[LoginLog](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[Email] [nvarchar](max) NULL,
[Platform] [nvarchar](max) NULL,
[Latitude] [nvarchar](max) NULL,
[Longitude] [nvarchar](max) NULL,
[InsertDate] [datetime] NOT NULL,
[ModifiedDate] [datetime] NULL,
[ipaddress] [nvarchar](55) NULL,
[City] [varchar](50) NULL,
[APP] [varchar](55) NULL,
[Country] [varchar](55) NULL,
PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
谢谢!
答案 0 :(得分:1)
我认为你无能为力。问题在于排序中的情况如果要杀死sql server可能做的任何优化。您应该查看查询计划,并添加一个重新编译,但在一天结束时 - 该查询不会有效。动态SQL是唯一有效的方法 - 从客户端,或通过sp中的字符串操作,然后执行命令来执行SQL字符串。
显然,非sargeable元素会杀死任何索引的使用 - 最后,设计数据库的人在这里做了一个非常无能的工作。没有正确的方法来有效地查询它。答案 1 :(得分:1)
正如我在评论部分中提到的,您的存储过程存在许多问题,因此很难指出一件事并说:“在这里,这就是问题所在,修复它并且你很好”。
我会列出一些跳出来的东西:
派生表混乱中的派生表中的派生表。
编译器通常擅长优化查询,前提是查询在派生表/子查询方面不是太深(即不太复杂)。如果您的查询变得太深,您应该考虑在临时表中填充派生表(如果需要,可以适当地编入索引)。
我知道这是一个非常广泛的陈述,很难确定你何时应该采用这种工作方式。像往常一样,证据就是吃布丁。
强制表扫描会破坏性能。
例如,您有一个确定MAX(id) FROM [LoginLog] ll2
的子查询。在该子查询中,WHERE子句的条件为ll2.email=ll.email
。如果LoginLog.email
上没有合适的INDEX,则会强制LoginLog
上的表扫描以查找相应的电子邮件地址。
该子句具有一个额外的复杂查找,其中包含一系列OR'ed LIKE语句,这些语句将强制进行表扫描。 SQL Server中没有布尔短路,因此即使您在LoginLog.email
上提供INDEX,也可能会进行表扫描以确定其他条件的状态。
如果您的查询包含Actual Execution Plan,则可以看到这些扫描。
尝试在一个查询中完成所有操作
完成所有操作的查询通常过于复杂而无法快速执行。考虑拆分用例,并为每个这样的用例创建一个更简单的查询。通常,具有少量参数的非复杂查询将更快地执行。
参数嗅探
我不打算详细介绍,网上有很多文章可以解释这一点(例如this one首先出现在我的搜索引擎中)。这种“参数嗅探”会损害存储过程的性能。第一次运行存储过程时,SQL Server编译器将创建一个针对传递给它的参数进行优化的执行计划。缓存这些编译的执行计划,以便编译器不必在每次执行时重新编译存储过程。存储过程的执行计划将在后续调用中重用,但是此执行计划对于其他参数可能完全没有效率。解决此问题的一种方法是为您的查询指定OPTION(OPTIMIZE FOR UNKNOWN)
。
其他评论
ORDER BY
子句太宽,如果结果集很大,可能会损害性能。您应该考虑创建动态SQL以仅对实际需要的列进行排序。
您正在使用@sp_search
查找first_log
,last_log
,platform
和app
中的文字...这看起来很傻,什么用例应该在如此多的文本列中找到意味着不同的文本?
没有索引(至少你没有显示任何索引)。如果查询表,则应提供合适的索引以加快它们的速度。否则,除非您要查找ID,否则您将强制进行表扫描。