MySQL疯狂跨表查询求助!
我需要执行这个查询,我必须解析与另一个表中的另一个字段相匹配的字段信息,然后在多个表中进行冲洗和重复,最终返回所需的行。
问题是,我怎样才能加快速度......它返回数十万行,并且对于我的客户在其管理部分来说效果不太好,因为查询导致崩溃。
以下是查询:
SELECT DISTINCT t1.CU_ship_name1, t1.CU_ship_name2, t1.CU_email
FROM (
SELECT CU_id, CU_ship_name1, CU_ship_name2, CU_email
FROM customers
WHERE CU_solicit=1
AND CU_cdate >=".$startDate."
AND CU_cdate <=".$endDate."
)AS t1
INNER JOIN orders AS t2 ON t1.CU_id = t2.O_cid
INNER JOIN item AS t3 ON t2.O_ref = t3.I_oref
INNER JOIN product AS t4 ON t3.I_pid = t4.P_id
INNER JOIN (
SELECT C_id FROM category WHERE C_store_type =1
) AS t5 ON t4.P_cat = t5.C_id
“客户”、“订单”、“项目”表每月更新数万个新行,“产品”表每月至少接收一百个新行。
我唯一能想到做的就是创建一个保存此信息的新表(这不是理想的解决方案),并向这些表添加索引。我担心索引,因为这些表获取了大量新数据,但我愿意尝试它(总是可以撤消它吗?)。但我不相信索引会自行解决问题。
更新:我现在正在使用这个查询并获得更快的结果,对所有 WHERE 和 JOIN ON 行建立索引根本没有多大帮助......我不明白为什么。
删除子查询:
对我的查询速度也产生了灾难性的影响,从下面查询的 3-4 秒到具有相同参数的 151 秒。
SELECT DISTINCT t1.CU_ship_name1, t1.CU_ship_name2, t1.CU_email
FROM customers AS t1
WHERE t1.CU_solicit=1
AND t1.CU_cdate>= 20100725000000
AND t1.CU_cdate<= 20100801000000
AND EXISTS(
SELECT NULL FROM orders AS t2
INNER JOIN item AS t3 ON t2.O_ref = t3.I_oref
INNER JOIN product AS t4 ON t3.I_pid = t4.P_id
INNER JOIN (
SELECT C_id
FROM category
WHERE C_store_type = 2
) AS t5 ON t4.P_cat = t5.C_id
WHERE t1.CU_id = t2.O_cid);
没关系,我将它们更改为正常连接并且没有子查询,并且在完成所有操作之后,这件事现在快如闪电。现在是查询:
SELECT DISTINCT t1.CU_ship_name1, t1.CU_ship_name2, t1.CU_email
FROM customers AS t1
JOIN orders AS t2 ON t1.CU_id = t2.O_cid
JOIN item AS t3 ON t2.O_ref = t3.I_oref
JOIN product AS t4 ON t3.I_pid = t4.P_id
JOIN category AS t5 ON t4.P_cat = t5.C_id
WHERE t1.CU_solicit =1
AND t1.CU_cdate >=20100425000000
AND t1.CU_cdate <=20100801000000
AND t5.C_store_type =2
I have this query I need to perform where I have to parse through a fields info matching it to another field in another table and then rinse and repeat across several tables, finally this results in the desired rows being returned.
The question is, how can I speed this up... it returns hundreds of thousands of rows and it's not working too well for my client in their admin section as the query is causing a crash.
Here is the query:
SELECT DISTINCT t1.CU_ship_name1, t1.CU_ship_name2, t1.CU_email
FROM (
SELECT CU_id, CU_ship_name1, CU_ship_name2, CU_email
FROM customers
WHERE CU_solicit=1
AND CU_cdate >=".$startDate."
AND CU_cdate <=".$endDate."
)AS t1
INNER JOIN orders AS t2 ON t1.CU_id = t2.O_cid
INNER JOIN item AS t3 ON t2.O_ref = t3.I_oref
INNER JOIN product AS t4 ON t3.I_pid = t4.P_id
INNER JOIN (
SELECT C_id FROM category WHERE C_store_type =1
) AS t5 ON t4.P_cat = t5.C_id
The 'customers','orders','item' tables get updated with tens of thousands of new rows every month and the 'product' table receives atleast one-hundred new rows every month.
The only thing I could think to do was to create a new table that holds this info (which is not an ideal solution), and add an index to these tables. I fear the index since these tables get such a large number of new data but I am willing to try it (can always undo it right?). However I do not believe that the index will fix the issue by itself.
UPDATE: I am now using this query and getting faster results, indexing all the WHERE and JOIN ON rows didn't help much at all...I can't figure out why.
Removing subqueries:
had a disasterous effect on my query speed as well from 3-4 seconds on the query below to 151 with the same perameters.
SELECT DISTINCT t1.CU_ship_name1, t1.CU_ship_name2, t1.CU_email
FROM customers AS t1
WHERE t1.CU_solicit=1
AND t1.CU_cdate>= 20100725000000
AND t1.CU_cdate<= 20100801000000
AND EXISTS(
SELECT NULL FROM orders AS t2
INNER JOIN item AS t3 ON t2.O_ref = t3.I_oref
INNER JOIN product AS t4 ON t3.I_pid = t4.P_id
INNER JOIN (
SELECT C_id
FROM category
WHERE C_store_type = 2
) AS t5 ON t4.P_cat = t5.C_id
WHERE t1.CU_id = t2.O_cid);
Nevermind, I changed them to normal joins and no subqueries and this thing is lightening fast now after everything. Here is the query now:
SELECT DISTINCT t1.CU_ship_name1, t1.CU_ship_name2, t1.CU_email
FROM customers AS t1
JOIN orders AS t2 ON t1.CU_id = t2.O_cid
JOIN item AS t3 ON t2.O_ref = t3.I_oref
JOIN product AS t4 ON t3.I_pid = t4.P_id
JOIN category AS t5 ON t4.P_cat = t5.C_id
WHERE t1.CU_solicit =1
AND t1.CU_cdate >=20100425000000
AND t1.CU_cdate <=20100801000000
AND t5.C_store_type =2
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我会索引您的 where Criteria 以及 ON 语句中的列。索引将立即解决您的崩溃问题,并且可能不会显着降低您的修改操作。每月数万行实际上并不是那么多行——除非您的数据库位于一台性能较弱的机器上。
此外,我会考虑完全删除子查询。它们经常会降低 SQL Server 的性能。您可能还想考虑将查询移动到存储过程中,以便服务器有机会缓存其执行计划。
I would index the columns in your where Criteria as well as in your ON statements. The indexes will immediately address your crashing problem, and probably not degrade your modify operations significantly. Tens of thousands of rows every month is not actually that many rows -- unless your DB is on a weak machine.
In addition, I would look into removing the subqueries entirely. They often slow down sql server performance. You may also want to look into moving the query into a stored procedure so the server has a chance at caching its execution plan.
我会尝试两件事:
1)在 ON 和 WHERE 子句中使用的列上添加索引
2)通过将子查询重写为正常的 JOIN 和 WHERE 条件来消除子查询
只有当您完成这些操作并发现您仍然有一个问题,你应该考虑其他选择。
除了不必要的子查询之外,这看起来确实是一个非常简单的查询。即使有数百万行,您也不会期望它会变慢,除非您没有定义索引,MySQL 可用的内存太少,或者您对 MySQL 服务器本身的可用资源配置很差。
每月一万行新行不算什么。您每隔几分钟就会插入一个新行。在决定定义哪些索引时,这甚至都不是考虑因素。廉价服务器上的 MySQL 每秒可以处理数百次插入。
I'd try two things:
1) Add indexes on the columns you use in the ON and WHERE clauses
2) Eliminate the subqueries by rewriting them as normal JOINs and WHERE conditions
Only once you've done those and found you're still having a problem should you consider other options.
This really looks like a pretty simple query, other than the unnecessary subqueries. You would not expect it to be slow with even millions of rows unless you don't have indexes defined, you have far too little memory available to MySQL, or you've configured the MySQL server itself very poorly for the resources available.
Ten thousand new rows a month is nothing. You're putting in a new row once every several minutes. That's not even a consideration when deciding what indexes to define. MySQL on a cheap server can handle hundreds of inserts per second.