在哪里处理数据? Db还是本地的?

时间:2014-03-25 08:00:39

标签: c# sql oracle linq

我们正在制定一个解决方案,该解决方案可以向三个不同国家/地区的三个不同的公共数据库发送许多搜索请求。 例如,搜索从一个数据库中提取数据并将其作为参数传递给另一个数据库。参数是一个列表,每个项目都需要与OR运算符逻辑连接。因此,我们最终得到一个sql select语句,在OR子句中链接了多达1000个where运算符。

现在我的问题是1000或500甚至5000个逻辑ANDOR select语句中的运算符使 db更慢并且我应该更好地请求所有数据到电脑,并在我的电脑上进行匹配。

数据量在5000到10000之间,我们正在谈论公共数据库,因此数量不断增长。

例如这样的sql语句:

select * from some_table
where .. and .. or .. or.. or..
      or.. or.. or.. or.. or.. or.. (1000 times)

如果我将所有数据提取到我的电脑,我可以使用LINQ语句进行过滤。

你建议我做什么?对这一个人的任何经历?

很抱歉,如果这是重复的,请在评论中告诉我,我会删除此问题。

修改

应该考虑许多用户可以同时访问数据库。

5 个答案:

答案 0 :(得分:1)

我总是了解到运行包含数百个OR语句的查询对性能不利。但是,即使在12g上运行示例,使用主键索引查询具有orin的表似乎也不会更改执行计划。

因此我说:没关系。您可以考虑的唯一事项是可读性,查询长度等。

不过,我个人更喜欢where in

使用示例数据查看this其他有用的问题。

答案 1 :(得分:1)

使用单个查询在数据库中处理所有内容。对数据库性能进行批处理通常是最好的事情。

查询中最昂贵的部分是从磁盘读取数据。一旦数据在内存中,过滤掉几千个条件就是少量的工作。您的本地处理器可能比数据库服务器更快。但这并不重要,因为如果您返回所有记录,您的计算机将花费太多时间在不必要的IO上。

此外,如果您每秒运行该查询一次,则SQL查询中的5000个条件只是一个问题。

答案 2 :(得分:0)

我想你应该试试。

创建一个尽可能简单但又复杂到现实的示例,然后使用某种形式的基准测试来运行它

无论哪种方式最适合您,您应该选择做什么。

修改:

那就是说 - 单个SQL语句中的大量和/或单一听起来很复杂和混乱。除非通过这种方式(?)实现真正的好处,否则我可能会尝试找到一种更简洁的方法来执行此操作,例如将操作拆分为几个步骤并应用Linq或类似的东西,即使只是为了使解决方案更易于管理。

答案 3 :(得分:0)

答案是 - 依赖

  1. 公共数据库的数据有多大?如果您要查询Google,则无法获取所有数据。

  2. 假设那些公共数据库的硬件和数据库调优比家用电脑强得多,这是合理的。

  3. 是否有一个选项可以从那些公共数据库中列出黑名单?

  4. 订单有关系吗?如果你查询db 1然后db 2会更快,那么查询db 2然后db 1?

  5. 主要是尝试&错误以及哪种方法最适合您并且可能。

答案 4 :(得分:0)

使用多个布尔运算符的ORACLE上的SQL查询

  

评论:我与数据库报告设计师CRYSTAL REPORTS合作多年。它是第一个基于GUI的拖放式工具之一,它使具有多个数据库背景的开发人员能够更轻松地构建具有多个表和过滤条件的查询。权衡的是该工具正在编写SQL。很多时候,由于运行报告文件的工作站不得不吸收正在查询的数这是十多年前的事了,但我看到其他下一代工具也会自动生成真正糟糕的 SQL代码。

     

没有多少软件可以弥补糟糕的数据库设计。你不是第一次就把一切都弄好了(正如其他人已经注意到的那样),但是当产品在真实世界中使用PERFORMANCE和{{1}的要求时,一点规划可以给一些喘息空间。 }。

演示模式和测试数据

以下解决方案是在SCALABILITY RDBMS系统上设计的。第一个表可以由数据库ORACLE 11g Release 2VIEWINLINE QUERYSUB QUERY或甚至MATERIALIZED VIEW输出表示,因此"属性&# 34;在此示例中讨论的可能来自多个表源和连接标准。

CURSOR

CREATE TABLE "ZZ_DATA_ATTRIBUTES" ( "DATA_ID" NUMBER(10,0) NOT NULL ENABLE, "NAME" VARCHAR2(50), "AGE" NUMBER(5,0), "HH_SIZE" NUMBER(5,0), "SURVEY_SCORE" NUMBER(5,0), "DMA_REGION" VARCHAR2(100), "LAST_CONTACT" DATE, CONSTRAINT "ZZ_DATA_ATTRIBUTES_PK" PRIMARY KEY ("DATA_ID") ENABLE ) / CREATE SEQUENCE "ZZ_DATA_ATTRIBUTES_SEQ" MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 41 CACHE 20 NOORDER NOCYCLE / CREATE OR REPLACE TRIGGER "BI_ZZ_DATA_ATTRIBUTES" before insert on "ZZ_DATA_ATTRIBUTES" for each row begin if :NEW."DATA_ID" is null then select "ZZ_DATA_ATTRIBUTES_SEQ".nextval into :NEW."DATA_ID" from sys.dual; end if; end; / ALTER TRIGGER "BI_ZZ_DATA_ATTRIBUTES" ENABLE / SEQUENCE个对象仅用于每个表上主键的唯一自动递增值。

TRIGGER

CREATE TABLE "ZZ_CONDITION_RESULTS" ( "RESULT_ID" NUMBER(10,0) NOT NULL ENABLE, "DATA_ID" NUMBER(10,0) NOT NULL ENABLE, "COND_ONE" NUMBER(10,0), "COND_TWO" NUMBER(10,0), "COND_THREE" NUMBER(10,0), "COND_FOUR" NUMBER(10,0), "COND_FIVE" NUMBER(10,0), CONSTRAINT "ZZ_CONDITION_RESULTS_PK" PRIMARY KEY ("RESULT_ID") ENABLE ) / ALTER TABLE "ZZ_CONDITION_RESULTS" ADD CONSTRAINT "ZZ_CONDITION_RESULTS_FK" FOREIGN KEY ("DATA_ID") REFERENCES "ZZ_DATA_ATTRIBUTES" ("DATA_ID") ENABLE / CREATE SEQUENCE "ZZ_CONDITION_RESULTS_SEQ" MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE / CREATE OR REPLACE TRIGGER "BI_ZZ_CONDITION_RESULTS" before insert on "ZZ_CONDITION_RESULTS" for each row begin if :NEW."RESULT_ID" is null then select "ZZ_CONDITION_RESULTS_SEQ".nextval into :NEW."RESULT_ID" from sys.dual; end if; end; / ALTER TRIGGER "BI_ZZ_CONDITION_RESULTS" ENABLE / 应为ZZ_CONDITION_RESULTS类型。它将包含每个布尔TABLE条件的结果。虽然1000列的列可能实际上不可行,但初始方法将显示如何排列大量布尔输出能够快速识别和隔离感兴趣的组合和模式。

示例数据

您可以选择自己的数据值,但这些值是为了使示例有效而创建的。我选择了OR的主题,其中汇总的数据是我们虚构的公司收集的关于客户的不同属性:客户名称,年龄,hh_size(家庭规模),一些基准测试的评分结果,DMA(人口统计营销区域)区域和客户上次联系的日期。

Test Marketing Data

使用Oracle包结构定义的布尔参数

初始设计是通过MARKETING计算业务逻辑。例如,在OP中:

Oracle PL/SQL Package Object

每个空白都是来自包中的单独Oracle函数调用。结果表示为已评估的每个属性记录的列值。

 select * from some_table
 where .. and .. or .. or.. or..
  or.. or.. or.. or.. or.. or.. (1000 times)

结束循环;
   COMMIT;

结束MAIN_DRIVER;

结束" ZZ_PKG_MARKETING_DEMO&#34 ;;

  

PL / SQL备注:有些人可能不熟悉 create or replace package ZZ_PKG_MARKETING_DEMO as c_result_true constant pls_integer:= 1; c_result_false constant pls_integer:= 0; cursor attrib_cur is select data_id, name, age, hh_size, survey_score, dma_region, last_contact from zz_data_attributes; TYPE attrib_record_type IS RECORD ( data_id zz_data_attributes.data_id%TYPE, name zz_data_attributes.name%TYPE, age zz_data_attributes.age%TYPE, hh_size zz_data_attributes.hh_size%TYPE, survey_score zz_data_attributes.survey_score%TYPE, dma_region zz_data_attributes.dma_region%TYPE, last_contact zz_data_attributes.last_contact%TYPE ); function evaluate_cond_one ( p_attrib_rec attrib_record_type) return pls_integer; function evaluate_cond_two ( p_attrib_rec attrib_record_type) return pls_integer; function evaluate_cond_three ( p_attrib_rec attrib_record_type) return pls_integer; function evaluate_cond_four ( p_attrib_rec attrib_record_type) return pls_integer; function evaluate_cond_five ( p_attrib_rec attrib_record_type) return pls_integer; procedure main_driver; end;​ create or replace package body "ZZ_PKG_MARKETING_DEMO" is function evaluate_cond_one ( p_attrib_rec attrib_record_type) return pls_integer as begin -- Checks if person is from a DMA Region in California. IF p_attrib_rec.dma_region like 'CA%' THEN return c_result_true; ELSE return c_result_false; END IF; end EVALUATE_COND_ONE; function evaluate_cond_two ( p_attrib_rec attrib_record_type) return pls_integer as c_begin_age_range constant zz_data_attributes.age%TYPE:= 20; c_end_age_range constant zz_data_attributes.age%TYPE:= 35; begin -- Part 1 of 2 Checks if person belongs to the 20 to 35 years age bracket IF p_attrib_rec.age between c_begin_age_range and c_end_age_range THEN return c_result_true; ELSE return c_result_false; END IF; end EVALUATE_COND_TWO; function evaluate_cond_three ( p_attrib_rec attrib_record_type) return pls_integer as c_lowest_age constant zz_data_attributes.age%TYPE:= 45; begin -- Part 2 of 2 Checks if person is from age 45 and up demographic. IF p_attrib_rec.age >= c_lowest_age THEN return c_result_true; ELSE return c_result_false; END IF; end EVALUATE_COND_THREE; function evaluate_cond_four ( p_attrib_rec attrib_record_type) return pls_integer as c_cutoff_score CONSTANT zz_data_attributes.survey_score%TYPE:= 1200; begin -- Checks if person's survey score is higher than c_cutoff_score IF p_attrib_rec.survey_score >= c_cutoff_score THEN return c_result_true; ELSE return c_result_false; END IF; end EVALUATE_COND_FOUR; function evaluate_cond_five ( p_attrib_rec attrib_record_type) return pls_integer as c_last_contact_period CONSTANT pls_integer:= -750; -- Note current date is anchored to a static value so the data output -- in this example will still work regardless of how old this post -- may get. c_current_date CONSTANT zz_data_attributes.last_contact%TYPE:= to_date('03/25/2014','MM/DD/YYYY'); begin -- Checks if person's last contact date has been in the last 750 -- days. IF p_attrib_rec.last_contact >= (c_current_date + c_last_contact_period) THEN return c_result_true; ELSE return c_result_false; END IF; end EVALUATE_COND_FIVE; procedure MAIN_DRIVER as v_rec_attr attrib_record_type; v_rec_cond zz_condition_results%ROWTYPE; begin for i in attrib_cur loop -- Set the input record variable with the attribute values queried by the -- current cursor. v_rec_attr.data_id := i.data_id; v_rec_attr.name := i.name; v_rec_attr.age := i.age; v_rec_attr.hh_size := i.hh_size; v_rec_attr.survey_score := i.survey_score; v_rec_attr.dma_region := i.dma_region; v_rec_attr.last_contact := i.last_contact; -- Set each condition column value equal to their matching package function. v_rec_cond.cond_one := evaluate_cond_one(p_attrib_rec => v_rec_attr); v_rec_cond.cond_two := evaluate_cond_two(p_attrib_rec => v_rec_attr); v_rec_cond.cond_three:= evaluate_cond_three(p_attrib_rec => v_rec_attr); v_rec_cond.cond_four := evaluate_cond_four(p_attrib_rec => v_rec_attr); v_rec_cond.cond_five := evaluate_cond_five(p_attrib_rec => v_rec_attr); INSERT INTO zz_condition_results (data_id, cond_one, cond_two, cond_three, cond_four, cond_five) VALUES ( v_rec_attr.data_id, v_rec_cond.cond_one, v_rec_cond.cond_two, v_rec_cond.cond_three, v_rec_cond.cond_four, v_rec_cond.cond_five ); ,例如程序CUSTOM DATA TYPES中程序包中定义的RECORD VARIABLE TYPE。它们使处理的数据更容易处理和参考识别。

简单英语的布尔算术(好吧,有点)

可以修改MAIN_DRIVER命名CURSOR以对单个记录或较小的输入数据集进行操作。现在,调用ATTRIB_CUR过程来处理属性数据源中的所有记录(同样,这不必是单个表)。

MAIN_DRIVER

现在已经为所有样本记录评估了每个示例条件,有几个更简单的路径来评估布尔值,当前捕获的值为" 1" (对于 BEGIN ZZ_PKG_MARKETING_DEMO.MAIN_DRIVER; END; )和" 0" (对于TRUE)。

如果只需要满足这一系列条件中的一个(如在FALSE运算符的长链中),则OR子句应如下所示:

WHERE

简写方法可能是:

 WHERE COND_ONE = 1 OR COND_TWO = 1 OR COND_THREE = 1 OR COND_FOUR = 1 OR COND_FIVE = 1
  

这买什么?通过在填充数据记录时处理其他静态评估(自定义条件),可以获得性能提升。一个很好的理由是,每个询问此标准的后续查询都不需要再次处理业务逻辑。我们还通过具有非常非常低的基数(TWO!)

的决策值来利用优势      

第二个"简写" WHERE过滤标准的一个例子是关于最终方法将如何管理数千"数千"布尔评估。

可扩展性:如何连续几万次这样做

假设这种方法可以扩展到OP中提出的幅度是不切实际的。最后一个问题:这个解决方案如何应用于一千个布尔值链?

  

提示: WHERE (COND_ONE + COND_TWO + COND_THREE + COND_FOUR + COND_FIVE) > 0 您的结果。

大量布尔条件的可扩展表设计

Pivoted Table Design

这里还有一个表的模型,其中包含样本数据的方式:

Organization of Data From Multiple Boolean Conditions

在五个样本条件之间获取多个PIVOT关系所需的SQL可以通过聚合查询来完成:

OR

退伍军人可能会注意到,使用支持数据库的 -- For multiple OR relations: SELECT DATA_ID FROM ZZ_CONDITION_PIVOT GROUP BY DATA_ID HAVING SUM(RESULT) > 0 可以进一步简化这种语法。

  

此设计应该是低维护,在实施期间或之后引入任意数量的布尔条件。表格设计应始终保持不变。

让我知道你的想法,看起来讨论已转移到其他问题和贡献者,所以这可能足够让你开始。向前!