ฉันกำลังมองหาคำแนะนำในการออกแบบตาราง / ดัชนีสำหรับสถานการณ์ต่อไปนี้:
ฉันมีตารางขนาดใหญ่ (ข้อมูลประวัติราคาหุ้น InnoDB 35 ล้านแถวและเพิ่มขึ้น) ด้วยคีย์หลักผสม (assetid (int) วันที่ (วันที่) นอกเหนือจากข้อมูลการกำหนดราคาแล้วฉันมี 200 ค่าสองเท่าที่จำเป็นต้องสอดคล้องกับแต่ละระเบียน
CREATE TABLE `mytable` (
`assetid` int(11) NOT NULL,
`date` date NOT NULL,
`close` double NOT NULL,
`f1` double DEFAULT NULL,
`f2` double DEFAULT NULL,
`f3` double DEFAULT NULL,
`f4` double DEFAULT NULL,
... skip a few …
`f200` double DEFAULT NULL,
PRIMARY KEY (`assetid`, `date`)) ENGINE=`InnoDB` DEFAULT CHARACTER SET latin1 COLLATE
latin1_swedish_ci ROW_FORMAT=COMPACT CHECKSUM=0 DELAY_KEY_WRITE=0
PARTITION BY RANGE COLUMNS(`date`) PARTITIONS 51;
ฉันเริ่มเก็บ 200 คอลัมน์คู่โดยตรงในตารางนี้เพื่อความสะดวกในการอัปเดตและดึงข้อมูลและสิ่งนี้ทำงานได้ดีเนื่องจากการสืบค้นเฉพาะที่ทำบนโต๊ะนี้คือสินทรัพย์และวันที่ (สิ่งเหล่านี้รวมอยู่ในแบบสอบถามใด ๆ กับตารางนี้อย่างเคร่งครัด) ) และมีการอ่านคอลัมน์ 200 คู่เท่านั้น ขนาดฐานข้อมูลของฉันอยู่ที่ประมาณ 45 กิ๊ก
อย่างไรก็ตามตอนนี้ฉันมีข้อกำหนดที่ฉันต้องสามารถสืบค้นตารางนี้ด้วยการรวมกันของ 200 คอลัมน์ (เช่นชื่อ f1, f2, ... f200) ตัวอย่างเช่น:
select from mytable
where assetid in (1,2,3,4,5,6,7,....)
and date > '2010-1-1' and date < '2013-4-5'
and f1 > -0.23 and f1 < 0.9
and f117 > 0.012 and f117 < .877
etc,etc
ฉันไม่เคยต้องจัดการกับข้อมูลจำนวนมากในอดีตมาก่อนดังนั้นสัญชาตญาณแรกของฉันก็คือดัชนีจำเป็นสำหรับแต่ละคอลัมน์ 200 เหล่านี้หรือฉันจะไขด้วยการสแกนตารางขนาดใหญ่ ฯลฯ สำหรับฉันนี่หมายความว่า ฉันต้องการตารางสำหรับแต่ละคอลัมน์ 200 คอลัมน์ที่มีคีย์หลักค่าและดัชนีค่า ดังนั้นฉันไปกับที่
CREATE TABLE `f1` (
`assetid` int(11) NOT NULL DEFAULT '0',
`date` date NOT NULL DEFAULT '0000-00-00',
`value` double NOT NULL DEFAULT '0',
PRIMARY KEY (`assetid`, `date`),
INDEX `val` (`value`)
) ENGINE=`InnoDB` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ROW_FORMAT=COMPACT CHECKSUM=0 DELAY_KEY_WRITE=0;
ฉันเติมและทำดัชนีทั้ง 200 ตารางแล้ว ฉันออกจากตารางหลักเหมือนเดิมโดยมีคอลัมน์ทั้งหมด 200 คอลัมน์เนื่องจากมีการสอบถามอย่างสม่ำเสมอในช่วงของสินทรัพย์และวันที่และเลือกคอลัมน์ทั้งหมด 200 คอลัมน์ ฉันคิดว่าการทิ้งคอลัมน์เหล่านั้นไว้ในตารางหลัก (ไม่ได้ทำดัชนี) เพื่อจุดประสงค์ในการอ่านและจากนั้นให้มีการจัดทำดัชนีไว้ในตารางของตนเอง (สำหรับการกรองแบบเข้าร่วม) จะเป็นสิ่งที่มีประสิทธิภาพมากที่สุด ฉันวิ่งไปอธิบายในรูปแบบใหม่ของแบบสอบถาม
select count(p.assetid) as total
from mytable p
inner join f1 f1 on f1.assetid = p.assetid and f1.date = p.date
inner join f2 f2 on f2.assetid = p.assetid and f2.date = p.date
where p.assetid in(1,2,3,4,5,6,7)
and p.date >= '2011-01-01' and p.date < '2013-03-14'
and(f1.value >= 0.96 and f1.value <= 0.97 and f2.value >= 0.96 and f2.value <= 0.97)
แน่นอนผลลัพธ์ที่ฉันต้องการได้รับการอธิบายแสดงให้ฉันเห็นว่าแถวที่สแกนมีขนาดเล็กกว่ามากสำหรับแบบสอบถามนี้ อย่างไรก็ตามฉันได้ผลข้างเคียงที่ไม่พึงประสงค์
1) ฐานข้อมูลของฉันเพิ่มจาก 45 กิ๊กเป็น 110 กิ๊ก ฉันไม่สามารถเก็บฐานข้อมูลไว้ใน RAM ได้อีกต่อไป (ฉันมี 256Gig of RAM ระหว่างทาง)
2) การแทรกข้อมูลใหม่ทุกคืนจะต้องทำ 200 ครั้งแทนที่จะเป็นหนึ่งครั้ง
3) การบำรุงรักษา / การดีแฟรกต์ของตารางใหม่ 200 ตารางใช้เวลานานกว่า 200 เท่าเพียง 1 ตาราง ไม่สามารถทำให้เสร็จในคืนเดียว
4) เคียวรีกับ f1, ตาราง ฯลฯ ไม่จำเป็นต้องมี performant ตัวอย่างเช่น:
select min(value) from f1
where assetid in (1,2,3,4,5,6,7)
and date >= '2013-3-18' and date < '2013-3-19'
แบบสอบถามด้านบนในขณะที่อธิบายแสดงให้เห็นว่ามันดูที่ <1,000 แถวสามารถใช้เวลา 30+ วินาทีให้เสร็จสมบูรณ์ ฉันคิดว่านี่เป็นเพราะดัชนีมีขนาดใหญ่เกินไปที่จะใส่ในหน่วยความจำ
นับว่าเป็นข่าวร้ายฉันจึงดูเพิ่มเติมและพบว่ามีการแบ่งพาร์ติชัน ฉันติดตั้งพาร์ติชั่นในตารางหลักโดยแบ่งพาร์ติชันตามวันที่ทุกๆ 3 เดือน ทุกเดือนดูเหมือนจะสมเหตุสมผลสำหรับฉัน แต่ฉันได้อ่านว่าเมื่อคุณได้รับพาร์ติชันมากกว่า 120 พาร์ติชันหรือมากกว่านั้น การแบ่งรายไตรมาสจะทิ้งฉันไว้ภายใต้นั้นในอีก 20 ปีข้างหน้า แต่ละพาร์ติชั่นอยู่ภายใต้ 2 กิ๊ก ฉันวิ่งอธิบายพาร์ทิชันและทุกอย่างดูเหมือนว่าจะถูกตัดอย่างเหมาะสมดังนั้นไม่ว่าฉันจะรู้สึกว่าการแบ่งเป็นขั้นตอนที่ดีอย่างน้อยที่สุดก็เพื่อวิเคราะห์ / เพิ่มประสิทธิภาพ / ซ่อมแซมวัตถุประสงค์
ฉันใช้เวลากับบทความนี้เป็นจำนวนมาก
http://ftp.nchu.edu.tw/MySQL/tech-resources/articles/testing-partitions-large-db.html
ปัจจุบันตารางของฉันถูกแบ่งพาร์ติชันโดยยังคงมีคีย์หลักอยู่ บทความระบุว่าคีย์หลักสามารถทำให้ตารางที่แบ่งพาร์ติชันได้ช้าลง แต่ถ้าคุณมีเครื่องที่สามารถจัดการกับมันได้คีย์หลักในตารางที่แบ่งพาร์ติชันจะเร็วขึ้น เมื่อรู้ว่าฉันมีเครื่องจักรขนาดใหญ่ระหว่างทาง (256 G RAM) ฉันก็ปล่อยปุ่มไว้
ตามที่ฉันเห็นนี่คือตัวเลือกของฉัน
ตัวเลือกที่ 1
1) ลบตารางพิเศษอีก 200 ตารางและให้แบบสอบถามทำการสแกนตารางเพื่อค้นหาค่า f1, f2 และอื่น ๆ ดัชนีที่ไม่ซ้ำกันอาจส่งผลกระทบต่อประสิทธิภาพการทำงานในตารางที่แบ่งพาร์ติชันอย่างถูกต้อง เรียกใช้คำอธิบายก่อนที่ผู้ใช้จะเรียกใช้คิวรีและปฏิเสธถ้าจำนวนแถวที่สแกนเกินเกณฑ์ที่กำหนด ช่วยตัวเองให้เจ็บปวดจากฐานข้อมูลยักษ์ Heck มันจะอยู่ในความทรงจำในไม่ช้า
ย่อยคำถาม:
มันดูเหมือนว่าฉันได้เลือกรูปแบบพาร์ทิชันที่เหมาะสม?
ตัวเลือก 2
แบ่งพาร์ติชันทั้งหมด 200 ตารางโดยใช้รูปแบบ 3 เดือนเดียวกัน เพลิดเพลินไปกับการสแกนแถวขนาดเล็กลงและอนุญาตให้ผู้ใช้เรียกใช้แบบสอบถามที่มีขนาดใหญ่ ตอนนี้พวกเขามีการแบ่งพาร์ติชั่นอย่างน้อยฉันก็สามารถจัดการพาร์ติชั่นได้ครั้งละ 1 อันเพื่อการบำรุงรักษา Heck มันจะอยู่ในความทรงจำในไม่ช้า พัฒนาวิธีที่มีประสิทธิภาพเพื่ออัปเดตพวกเขาทุกคืน
ย่อยคำถาม:
คุณเห็นเหตุผลที่ฉันอาจหลีกเลี่ยงดัชนีคีย์หลักในตาราง f1, f2, f3, f4 ... เหล่านี้หรือไม่โดยรู้ว่าฉันมีสินทรัพย์และวันที่เสมอเมื่อทำการสอบถาม ดูเหมือนว่าง่ายสำหรับฉัน แต่ฉันไม่คุ้นเคยกับชุดข้อมูลขนาดนี้ ที่จะหดฐานข้อมูลพวงฉันถือว่า
ตัวเลือก 3
ดร็อปคอลัมน์ f1, f2, f3 ในตารางต้นแบบเพื่อเรียกคืนพื้นที่นั้น จะเข้าร่วม 200 หากฉันต้องการอ่าน 200 คุณสมบัติบางทีมันอาจจะไม่ช้าอย่างที่มันฟัง
ตัวเลือก 4
พวกคุณทุกคนมีวิธีที่ดีกว่าในการสร้างโครงสร้างนี้มากกว่าที่ฉันเคยคิด
*หมายเหตุ: อีกไม่นานฉันจะเพิ่มอีก 50-100 ค่าสองเท่าเหล่านี้ให้กับแต่ละรายการดังนั้นฉันต้องออกแบบให้รู้ว่ากำลังจะมาถึง
ขอบคุณสำหรับความช่วยเหลือใด ๆ
อัปเดต # 1 - 3/24/2013
ฉันไปกับแนวคิดที่เสนอในความคิดเห็นที่ฉันได้ด้านล่างและสร้างตารางใหม่หนึ่งตารางโดยมีการตั้งค่าต่อไปนี้:
create table 'features'{
assetid int,
date date,
feature varchar(4),
value double
}
ฉันแบ่งพาร์ติชันตารางเป็นระยะเวลา 3 เดือน
ฉันเป่าไป 200 ตารางก่อนหน้านี้เพื่อให้ฐานข้อมูลของฉันกลับไปที่ 45 Gigg และเริ่มเติมตารางใหม่นี้ หนึ่งวันครึ่งหลังจากนั้นก็เสร็จสิ้นและฐานข้อมูลของฉันตอนนี้อยู่ที่ 220 Gigs!
มันอนุญาตให้ลบค่า 200 ค่าเหล่านี้ออกจากตารางหลักได้เนื่องจากฉันสามารถรับค่าได้จากการเข้าร่วมครั้งเดียว แต่นั่นจะทำให้ฉันได้รับ 25 Gigs หรือมากกว่านั้น
ฉันขอให้มันสร้างคีย์หลักบน assetid, วันที่, คุณสมบัติและดัชนีตามตัวอักษรและหลังจาก 9 ชั่วโมงของการสับมันไม่ได้ทำให้บุ๋มและดูเหมือนจะแข็งขึ้นดังนั้นฉันจึงฆ่าส่วนนั้นออก
ฉันสร้างพาร์ติชั่นใหม่สองสามอัน แต่ดูเหมือนว่าจะไม่ได้เรียกคืน / พื้นที่ใดเลย
ดังนั้นวิธีการแก้ปัญหาดูเหมือนว่ามันอาจจะไม่เหมาะ แถวใช้พื้นที่มากกว่าคอลัมน์ที่ฉันสงสัยหรือเปล่านั่นอาจเป็นสาเหตุที่โซลูชันนี้ใช้พื้นที่มากขึ้นหรือไม่
ฉันเจอบทความนี้:
http://www.chrismoos.com/2010/01/31/mysql-partitioning-tables-with-millions-of-rows
มันทำให้ฉันมีความคิด มันบอกว่า:
ตอนแรกฉันคิดถึง RANGE การแบ่งพาร์ติชันตามวันที่และในขณะที่ฉันใช้วันที่ในเคียวรีของฉันมันเป็นเรื่องธรรมดามากที่เคียวรีจะมีช่วงวันที่ที่ใหญ่มากซึ่งหมายความว่ามันสามารถขยายพาร์ติชันทั้งหมดได้อย่างง่ายดาย
ตอนนี้ฉันกำลังแบ่งพาร์ติชันตามวันที่เช่นกัน แต่จะอนุญาตให้ค้นหาด้วยช่วงวันที่ขนาดใหญ่ซึ่งจะลดประสิทธิภาพของการแบ่งพาร์ติชันของฉัน ฉันจะมีช่วงวันที่เสมอเมื่อฉันค้นหา แต่ฉันจะมีรายการสินทรัพย์อยู่ด้วยเสมอ บางทีโซลูชันของฉันควรแบ่งพาร์ติชันตามวันที่ซึ่งฉันมักจะระบุช่วงการสืบค้นของทรัพย์สิน (ซึ่งฉันสามารถหาได้มีรายการมาตรฐาน S&P 500 รัสเซล 2000 เป็นต้น) ด้วยวิธีนี้ฉันแทบจะไม่เคยดูชุดข้อมูลทั้งหมด
จากนั้นอีกครั้งฉันเป็นคนสำคัญในสินทรัพย์และวันที่ใด ๆ ดังนั้นอาจจะไม่ช่วยมาก
ความคิด / ความคิดเห็นใด ๆ เพิ่มเติมจะได้รับการชื่นชม
(value_name varchar(20), value double)
จะสามารถที่จะเก็บทุกอย่าง (value_name
เป็นf1
,f2
, ... )