我有以下查询,效率不高,很多时候会带回内存消息,有人可以提出任何建议来帮助加快速度吗? 谢谢 吉姆
DECLARE @period_from INT
SET @period_from = 201400
DECLARE @period_to INT
SET @period_to = 201414
Declare @length INT
Set @length = '12'
DECLARE @query VARCHAR(MAX)
SET @query = '%[^-a-zA-Z0-9() ]%'
SELECT 'dim_2' AS field, NULL AS Length, * FROM table1 WHERE client = 'CL'AND period >= @period_from AND @period_to <= @period_to AND dim_2 LIKE @query
UNION
SELECT 'dim_3' AS field, NULL AS Length, * FROM table1 WHERE client = 'CL'AND period >= @period_from AND @period_to <= @period_to AND dim_3 LIKE @query
UNION
SELECT 'dim_4' AS field, NULL AS Length, * FROM table1 WHERE client = 'CL'AND period >= @period_from AND @period_to <= @period_to AND dim_4 LIKE @query
UNION
SELECT 'dim_5' AS field, NULL AS Length, * FROM table1 WHERE client = 'CL'AND period >= @period_from AND @period_to <= @period_to AND dim_5 LIKE @query
UNION
SELECT 'dim_6' AS field, NULL AS Length, * FROM table1 WHERE client = 'CL'AND period >= @period_from AND @period_to <= @period_to AND dim_6 LIKE @query
UNION
SELECT 'dim_7' AS field, NULL AS Length,* FROM table1 WHERE client = 'CL'AND period >= @period_from AND @period_to <= @period_to AND dim_7 LIKE @query
UNION
SELECT 'ext_inv_ref' AS field, NULL AS Length, * FROM table1 WHERE client = 'CL'AND period >= @period_from AND @period_to <= @period_to AND ext_inv_ref LIKE @query
UNION
SELECT 'ext_ref' AS field, NULL AS Length, * FROM table1 WHERE client = 'CL'AND period >= @period_from AND @period_to <= @period_to AND ext_ref LIKE @query
UNION
SELECT 'description' AS field, NULL AS Length, * FROM table1 WHERE client = 'CL'AND period >= @period_from AND @period_to <= @period_to AND description LIKE @query
UNION
SELECT 'Length dim_2' AS field,LEN(dim_2) as Length, * FROM table1 WHERE client = 'CL'AND period >= @period_from AND @period_to <= @period_to AND dim_2 is not null and len(dim_2) >@length
UNION
SELECT 'Length dim_3' AS field, LEN(dim_3) as Length, * FROM table1 WHERE client = 'CL'AND period >= @period_from AND @period_to <= @period_to AND dim_3 is not null and len(dim_3) >@length
UNION
SELECT 'Length dim_4' AS field, LEN(dim_4) as Length, * FROM table1 WHERE client = 'CL'AND period >= @period_from AND @period_to <= @period_to AND dim_4 is not null and len(dim_4) >@length
UNION
SELECT 'Length dim_5' AS field, LEN(dim_5) as Length, * FROM table1 WHERE client = 'CL'AND period >= @period_from AND @period_to <= @period_to AND dim_5 is not null and len(dim_5) >@length
UNION
SELECT 'Length dim_6' AS field, LEN(dim_6) as Length, * FROM table1 WHERE client = 'CL'AND period >= @period_from AND @period_to <= @period_to AND dim_6 is not null and len(dim_6) >@length
UNION
SELECT 'Length dim_7' AS field, LEN(dim_7) as Length, * FROM table1 WHERE client = 'CL'AND period >= @period_from AND @period_to <= @period_to AND dim_7 is not null and len(dim_7) >@length
答案 0 :(得分:2)
我认为你不能优化这么多。数据库具有dim1到dim7作为一个表的列。现在,您希望将它们视为独立列。因此数据库设计不能满足您的要求。如果这只是一个例外,那么你将不得不忍受它。如果这种用法成为典型访问,那么应该考虑更改数据库设计并为维度添加一个附加表。
您不必要地做的一件事是使用 UNION ,这使得dbms可以查找重复项。由于您的记录以每个联合组的不同常量开始,因此没有。请改用 UNION ALL 。
答案 1 :(得分:1)
您可以显着减少联合的数量,但是工作会进入WHERE子句。 SQL查询优化器应该知道您只需要为每个union语句遍历表中的行一次,因此它应该更快。试试吧,看看!
SELECT
CASE
WHEN dim_2 like @query Then 'dim_2'
WHEN dim_3 like @query Then 'dim_3'
WHEN dim_4 like @query Then 'dim_4'
WHEN dim_5 like @query Then 'dim_5'
WHEN dim_6 like @query Then 'dim_6'
WHEN dim_7 like @query Then 'dim_7'
WHEN ext_inv_ref LIKE @query Then 'ext_inv_ref'
WHEN ext_ref LIKE @query Then 'ext_ref'
END AS field,
NULL AS Length,
*
FROM table1
WHERE client = 'CL'AND period >= @period_from AND @period_to <= @period_to
AND (dim_2 LIKE @query
OR dim_3 LIKE @query
OR dim_4 LIKE @query
OR dim_5 LIKE @query
OR dim_6 LIKE @query
OR dim_7 LIKE @query
OR ext_inv_ref LIKE @query
OR ext_ref LIKE @query)
UNION
SELECT
CASE
WHEN dim_2 is not null and len(dim_2) >@length Then 'Length dim_2'
WHEN dim_3 is not null and len(dim_3) >@length Then 'Length dim_3'
....
END AS field,
LEN(dim_2) as Length,
*
FROM table1
WHERE client = 'CL'AND period >= @period_from AND @period_to <= @period_to
AND ((dim_2 is not null and len(dim_2) >@length)
OR
(dim_3 is not null and len(dim_3) >@length)
OR ....
)
答案 2 :(得分:0)
有许多事情要做,但你可以这样做:
CREATE TEMPORARY TABLE temp_table1
SELECT * FROM table WHERE client = 'CL'
AND period >= @period_from AND @period_to <= @period_to;
然后使用此表作为其他联合的基础,然后删除它。如果经常进行此类选择,则在创建该临时表时,在table1中的字段period
和client
上引入复合索引也可能有所帮助:
ALTER TABLE table1 ADD KEY period_client (client, period);
答案 3 :(得分:0)
您可以做的最重要的事情是,如果它在您的权力范围内,就是重新构建数据库,以便将dim
字段移动到单独的表中,并且只有一个dim
列table(但对于那些有多个dim
值的情况,不止一行)。此过程称为数据库规范化。然后,您就可以使用一个SELECT
执行查询,而无需UNION
一起SELECT
个。{/ p>
对于写入的查询(这适用于具有更正的数据库结构的改进查询),您需要确定是否使用索引来解决查询。在您的情况下,最佳索引将是(client, period)
或(period, client)
之一,具体取决于这些索引的基数(基本上,这些列中存在多少个不同的值以及如何均匀地分配这些值。)
如果您已经拥有这些索引中的一个或两个,那么在没有重构数据库的情况下,您无能为力。如果不这样做,您可以尝试依次创建每个索引并查看它是否对查询时间产生影响。
答案 4 :(得分:0)
SELECT T.field
,T.Length
,table1.*
FROM table1
CROSS APPLY (
VALUES ('dim_2', dim_2, NULL)
,('dim_3', dim_3, NULL)
,...
,('Length dim_2', NULL, LEN(dim_2))
,...
) AS T(field, value, Length)
WHERE table1.client = 'CL'
AND table1.period BETWEEN @period_from AND @period_to
AND ((T.Length IS NOT NULL AND T.Length > @Length)
OR (T.value IS NOT NULL AND T.value LIKE @Query))
答案 5 :(得分:0)
您选择结果的方式会耗费大量时间,因为您每次都会查询每次记录所需的数据集,我的解决方案是查询一次并立即获得最终结果:
/* Part 1 : We will define a function that will help us to decompose a value of a column to multiple rows */
ALTER FUNCTION [audit].[FN_Decompose](@p_liste VARCHAR (MAX), @p_separateur CHAR(1))
RETURNS @table_result TABLE ([id] INT, [indexAt] INT, [element] VARCHAR (255) NULL)
AS
BEGIN
DECLARE @v_index INT
,@v_i INT
,@v_longueur INT
,@v_element VARCHAR(MAX)
IF ISNULL(@p_liste, '') <> ''
BEGIN
SET @v_index = 1
SET @v_i = 1
SET @v_longueur = LEN(@p_liste) + 2
SET @v_element = ''
--pour chaque caractère de la liste
WHILE @v_index <> @v_longueur
BEGIN
--si le caractère n''est pas un séparateur
IF SUBSTRING(@p_liste, @v_index, 1) <> @p_separateur
BEGIN
--Ajouter le caractère à l''élément courant
SET @v_element = @v_element + SUBSTRING(@p_liste, @v_index,1)
END
ELSE
BEGIN
--si l''élément courant n''est pas vide
--IF (@v_element <> '')
begin
--Ajout à la table
INSERT INTO @table_result ([id],[indexAt],element)
VALUES (@v_i, @v_index, @v_element)
--Ré-initialisation
SET @v_element = ''
SET @v_i = @v_i + 1
END
END
-- Caractère suivant
SET @v_index = @v_index + 1
END
END
INSERT INTO @table_result VALUES (@v_i, @v_index, @v_element)
RETURN
END
GO
/* THE Script */
DECLARE @period_from INT
SET @period_from = 201400
DECLARE @period_to INT
SET @period_to = 201414
Declare @length INT
Set @length = '12'
DECLARE @query VARCHAR(MAX)
SET @query = '%[^-a-zA-Z0-9() ]%';
WITH Temp AS (
SELECT
LEN(dim_2) AS Length_dim2
,LEN(dim_3) AS Length_dim3
,LEN(dim_4) AS Length_dim4
,LEN(dim_5) AS Length_dim5
,LEN(dim_6) AS Length_dim6
,LEN(dim_7) AS Length_dim7
,CASE WHEN dim_1 LIKE @query THEN 'dim_1' ELSE '' END+';'
+CASE WHEN dim_2 LIKE @query THEN 'dim_2' ELSE '' END+';'
+CASE WHEN dim_3 LIKE @query THEN 'dim_3' ELSE '' END+';'
+CASE WHEN dim_4 LIKE @query THEN 'dim_4' ELSE '' END+';'
+CASE WHEN dim_5 LIKE @query THEN 'dim_5' ELSE '' END+';'
+CASE WHEN dim_6 LIKE @query THEN 'dim_6' ELSE '' END+';'
+CASE WHEN dim_7 LIKE @query THEN 'dim_7' ELSE '' END+';'
+CASE WHEN ext_inv_ref LIKE @query THEN 'ext_inv_ref' ELSE '' END+';'
+CASE WHEN ext_ref LIKE @query THEN 'ext_ref' ELSE '' END+';'
+CASE WHEN [description] LIKE @query THEN 'description' ELSE '' END+';'
+CASE WHEN AND dim_2 is not null and len(dim_2) >@length THEN 'Length dim_2' ELSE '' END+';'
+CASE WHEN AND dim_3 is not null and len(dim_3) >@length THEN 'Length dim_3' ELSE '' END+';'
+CASE WHEN AND dim_4 is not null and len(dim_4) >@length THEN 'Length dim_4' ELSE '' END+';'
+CASE WHEN AND dim_5 is not null and len(dim_5) >@length THEN 'Length dim_5' ELSE '' END+';'
+CASE WHEN AND dim_6 is not null and len(dim_6) >@length THEN 'Length dim_6' ELSE '' END+';'
+CASE WHEN AND dim_7 is not null and len(dim_7) >@length THEN 'Length dim_7' ELSE '' END+';' AS fields
FROM table1
WHERE client = 'CL'
AND period >= @period_from
AND @period_to <= @period_to)
SELECT
CASE fn.element
WHEN 'Length dim_2' THEN Length_dim2
WHEN 'Length dim_3' THEN Length_dim3
WHEN 'Length dim_4' THEN Length_dim4
WHEN 'Length dim_5' THEN Length_dim5
WHEN 'Length dim_6' THEN Length_dim6
WHEN 'Length dim_7' THEN Length_dim7
END AS [Length]
,fn.element AS Field
,t.* /* The other columns */
FROM Temp t
CROSS APPLY [audit].[FN_Decompose](fields,';') fn
WHERE fn.element IS NOT NULL
祝你好运:)
答案 6 :(得分:0)
只是为了扩展我的评论,如果您有SQLServer 2005或更高版本,您可以取消数据以将列转换为行而不是检查
SELECT id, column_name, value
FROM (SELECT id, period, dim_2, dim_3, dim_4, dim_5, dim_6
, dim_7, ext_inv_ref, ext_ref, description
FROM myTable) a
UNPIVOT
(value FOR column_name
IN (dim_2, dim_3, dim_4, dim_5, dim_6
, dim_7, ext_inv_ref, ext_ref, description)
) unpvt
WHERE (value LIKE '%[^-a-zA-Z0-9() ]%' OR len(value) > 12)
AND period BETWEEN 201400 AND 201414